Commit 33969ba9 authored by bluebird's avatar bluebird

init

parents
Pipeline #5903 canceled with stages
{
"env": {
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
}
}
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
module.exports = {
root: true,
env: {
browser: true,
node: true
},
extends: [
'@nuxtjs/eslint-config-typescript',
'plugin:nuxt/recommended'
],
plugins: [
],
// add your custom rules here
rules: {}
}
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE / Editor
.idea
# Service worker
sw.*
# macOS
.DS_Store
# Vim swap files
*.swp
# mc-app-packger
## Build Setup
```bash
# install dependencies
$ yarn install
# serve with hot reload at localhost:3000
$ yarn dev
# build for production and launch server
$ yarn build
$ yarn start
# generate static project
$ yarn generate
```
For detailed explanation on how things work, check out the [documentation](https://nuxtjs.org).
## Special Directories
You can create the following extra directories, some of which have special behaviors. Only `pages` is required; you can delete them if you don't want to use their functionality.
### `assets`
The assets directory contains your uncompiled assets such as Stylus or Sass files, images, or fonts.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/assets).
### `components`
The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/components).
### `layouts`
Layouts are a great help when you want to change the look and feel of your Nuxt app, whether you want to include a sidebar or have distinct layouts for mobile and desktop.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/layouts).
### `pages`
This directory contains your application views and routes. Nuxt will read all the `*.vue` files inside this directory and setup Vue Router automatically.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/get-started/routing).
### `plugins`
The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use `Vue.use()`, you should create a file in `plugins/` and add its path to plugins in `nuxt.config.js`.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/plugins).
### `static`
This directory contains your static files. Each file inside this directory is mapped to `/`.
Example: `/static/robots.txt` is mapped as `/robots.txt`.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/static).
### `store`
This directory contains your Vuex store files. Creating a file in this directory automatically activates Vuex.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/store).
<template>
<!-- Main table element -->
<b-container>
<b-row>
<b-form-group
label="Filter"
label-for="filter-input"
label-cols-sm="3"
label-align-sm="right"
label-size="sm"
class="mb-0"
>
<b-input-group size="sm">
<b-form-input
id="filter-input"
v-model="filter"
type="search"
placeholder="Type to Search"
/>
<b-input-group-append>
<b-button :disabled="!filter" @click="filter = ''">
Clear
</b-button>
</b-input-group-append>
</b-input-group>
</b-form-group>
</b-row>
<b-table
:items="items"
:fields="fields"
:filter="filter"
responsive
>
<template #cell(operate)="row">
<b-btn :href="'/app/'+row.item.id">
update
</b-btn>
<b-btn :href="'/version/'+row.item.id">
upload verion
</b-btn>
<b-btn @click="delete_app(row.item)">
delete
</b-btn>
</template>
</b-table>
</b-container>
</template>
<script>
import Vue from 'vue'
import _ from 'lodash'
export default Vue.extend({
name: 'AppList',
data () {
return {
fields: ['id', 'author', 'name', 'operate'],
items: [
],
filter: null
}
},
mounted () {
this.$axios.get('/release/api/app').then((response) => {
if (response.data.success === true) {
for (const info of response.data.data) {
this.items.push({ id: info.id, author: _.get(info.appData, 'author'), name: _.get(_.get(info.appData, 'name'), 'zh-CN') })
}
} else {
this.msg = response.data.message
}
})
},
methods: {
delete_app (item) {
this.$axios.delete(`/release/api/admin/app/${item.id}`).then((response) => {
if (response.data.success === true) {
this.$bvToast.toast('delete ok', {
autoHideDelay: 1000,
title: 'hint'
})
} else {
this.$bvToast.toast(response.data.message, {
autoHideDelay: 1000,
title: 'hint'
})
}
})
}
}
})
</script>
<style scoped>
</style>
<template>
<div>
<b-button v-b-modal.create-app pill variant="info" size="lg">
create app
</b-button>
<b-modal
id="create-app"
ref="modal"
title="input app name"
@show="resetModal"
@hidden="resetModal"
@ok="handleOk"
>
<form ref="form" @submit.stop.prevent="handleSubmit">
<b-form-group
label="Name"
label-for="name-input"
invalid-feedback="AppName is required"
>
<b-form-input
id="name-input"
v-model="app_name"
required
/>
</b-form-group>
</form>
</b-modal>
</div>
</template>
<script>
import Vue from 'vue'
export default Vue.extend({
name: 'CreateAppBtn',
data () {
return {
app_name: ''
}
},
methods: {
create_app () {
this.$axios.put(`/release/api/admin/app/${this.app_name}`).then((response) => {
if (response.data.success === true) {
this.$bvToast.toast('create ok', {
autoHideDelay: 1000,
title: 'hint'
})
} else {
this.$bvToast.toast(response.data.message,
{
autoHideDelay: 1000,
title: 'error'
})
}
})
},
checkFormValidity () {
const valid = this.$refs.form.checkValidity()
this.nameState = valid
return valid
},
resetModal () {
this.app_name = ''
},
handleOk (bvModalEvt) {
// Prevent modal from closing
bvModalEvt.preventDefault()
// Trigger submit handler
this.handleSubmit()
},
handleSubmit () {
// Exit when the form isn't valid
if (!this.checkFormValidity()) {
return
}
// Push the name to submitted names
// Hide the modal manually
this.$nextTick(() => {
this.$bvModal.hide('create-app')
})
this.create_app()
return false
}
}
})
</script>
<style scoped>
</style>
<template>
<div>
<div>
<b-alert v-show="show" show variant="danger">
{{ msg }}
</b-alert>
</div>
<b-form @submit="onSubmit">
<h3>Sign In</h3>
<div class="form-group">
<label>Username</label>
<input v-model="form.username" type="text" class="form-control form-control-lg">
</div>
<div class="form-group">
<label>Password</label>
<input v-model="form.password" type="password" class="form-control form-control-lg">
</div>
<button type="submit" class="btn btn-dark btn-lg btn-block">
Sign In
</button>
</b-form>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'LoginForm',
data () {
return {
form: {
username: 'bluebirdsecuri@gmail.com',
password: 'C6dD$stndv&peG'
},
show: false,
msg: ''
}
},
methods: {
onSubmit (event: { preventDefault: () => void }) {
event.preventDefault()
this.$axios.post(
'/accounts/signin',
{
account: this.form.username,
password: this.form.password
}).then((response) => {
if (response.data.message != null) {
this.msg = response.data.message
this.show = true
return
}
const d = new Date()
d.setTime(d.getTime() + 1 * 24 * 60 * 60 * 1000)
const expires = 'expires=' + d.toUTCString()
document.cookie =
'Token=' + response.data.token + ';' + expires + ';path=/'
window.location.href = '/manager'
}).catch((error) => {
this.msg = error
this.show = true
console.log(this.msg)
console.log(error)
})
}
}
})
</script>
<style scoped>
body,
html,
.App,
.vue-tempalte,
.vertical-center {
width: 100%;
height: 100%;
}
.navbar-light {
background-color: #ffffff;
box-shadow: 0px 14px 80px rgba(34, 35, 58, 0.2);
}
.vertical-center {
display: flex;
text-align: left;
justify-content: center;
flex-direction: column;
}
.inner-block {
width: 450px;
margin: auto;
background: #ffffff;
box-shadow: 0px 14px 80px rgba(34, 35, 58, 0.2);
padding: 40px 55px 45px 55px;
border-radius: 15px;
transition: all .3s;
}
.vertical-center .form-control:focus {
border-color: #2554FF;
box-shadow: none;
}
.vertical-center h3 {
text-align: center;
margin: 0;
line-height: 1;
padding-bottom: 20px;
}
label {
font-weight: 500;
}
.forgot-password,
.forgot-password a {
text-align: right;
font-size: 13px;
padding-top: 10px;
color: #7a7a7a;
margin: 0;
}
.forgot-password a {
color: #2554FF;
}
.social-icons {
text-align: center;
font-family: "Open Sans";
font-weight: 300;
font-size: 1.5em;
color: #222222;
}
.social-icons ul {
list-style: none;
margin: 0;
padding: 0;
}
.social-icons ul li {
display: inline-block;
zoom: 1;
width: 65px;
vertical-align: middle;
border: 1px solid #e3e8f9;
font-size: 15px;
height: 40px;
line-height: 40px;
margin-right: 5px;
background: #f4f6ff;
}
.social-icons ul li a {
display: block;
font-size: 1.4em;
margin: 0 5px;
text-decoration: none;
}
.social-icons ul li a i {
-webkit-transition: all 0.2s ease-in;
-moz-transition: all 0.2s ease-in;
-o-transition: all 0.2s ease-in;
-ms-transition: all 0.2s ease-in;
transition: all 0.2s ease-in;
}
.social-icons ul li a:focus i,
.social-icons ul li a:active i {
transition: none;
color: #222222;
}
</style>
module.exports = {
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: [
'ts',
'js',
'vue',
'json'
],
transform: {
'^.+\\.ts$': 'ts-jest',
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
],
testEnvironment: 'jsdom'
}
export default {
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
ssr: false,
// Target: https://go.nuxtjs.dev/config-target
target: 'static',
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
title: 'mc-app-packger',
htmlAttrs: {
lang: 'en'
},
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' },
{ name: 'format-detection', content: 'telephone=no' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
// Global CSS: https://go.nuxtjs.dev/config-css
css: [
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
// https://go.nuxtjs.dev/typescript
'@nuxt/typescript-build'
],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/bootstrap
'bootstrap-vue/nuxt',
// https://go.nuxtjs.dev/axios
'@nuxtjs/axios'
],
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
baseURL: process.env.API_URL,
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
}
}
{
"name": "mc-app-packger",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
"lint": "yarn lint:js",
"test": "jest"
},
"dependencies": {
"@nuxtjs/axios": "^5.13.6",
"bootstrap": "^4.6.0",
"bootstrap-vue": "^2.21.2",
"core-js": "^3.15.1",
"nuxt": "^2.15.7",
"vue-cookies-ts": "^1.5.19",
"vue-json-editor": "^1.4.3"
},
"devDependencies": {
"@babel/eslint-parser": "^7.14.7",
"@nuxt/types": "^2.15.7",
"@nuxt/typescript-build": "^2.1.0",
"@nuxtjs/eslint-config-typescript": "^6.0.1",
"@nuxtjs/eslint-module": "^3.0.2",
"@vue/test-utils": "^1.2.1",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^27.0.5",
"eslint": "^7.29.0",
"eslint-plugin-nuxt": "^2.0.0",
"eslint-plugin-vue": "^7.12.1",
"jest": "^27.0.5",
"ts-jest": "^27.0.3",
"vue-jest": "^3.0.4"
}
}
<template>
<b-container>
<b-row>
<b-col lg="12">
<vue-json-editor v-model="json" :show-btns="true" :expanded-on-start="true" @json-save="onJsonSave" />
</b-col>
<b-col />
</b-row>
</b-container>
</template>
<script >
import Vue from 'vue'
import VueCookies from 'vue-cookies-ts'
import vueJsonEditor from 'vue-json-editor'
Vue.use(VueCookies)
export default Vue.extend({
name: 'App',
components: {
vueJsonEditor
},
data () {
return {
json: ''
}
},
mounted () {
const token = this.$cookies.get('Token')
if (token == null) {
window.location.href = '/login'
return
}
this.$axios.defaults.headers.common.Authorization = `Bearer ${token}`
this.$axios.get(`/release/api/app?id=${this.$route.params.id}`).then((response) => {
if (response.data.success === true) {
// this.json = JSON.stringify(response.data.data[0].appData).replace(/"([^"]+)":/g, '$1:')
this.json = response.data.data[0].appData || {}
} else {
this.$bvToast.toast('req error', {
autoHideDelay: 1000,
title: 'error'
})
}
})
},
methods: {
onJsonSave (json) {
this.$axios.post('/release/api/app?id=' + this.$route.params.id, json).then((response) => {
if (response.data.success === true) {
// this.json = JSON.stringify(response.data.data[0].appData).replace(/"([^"]+)":/g, '$1:')
// this.json = response.data.data[0].appData || {}
this.$bvToast.toast('update ok', {
autoHideDelay: 1000,
title: 'success'
})
} else {
this.$bvToast.toast(response.data.message, {
autoHideDelay: 1000,
title: 'error'
})
}
}).catch((error) => {
this.$bvToast.toast(error, {
autoHideDelay: 1000,
title: 'error'
})
})
}
}
})
</script>
<style scoped>
</style>
<template />
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
mounted () {
window.location.href = '/manager'
}
})
</script>
<template>
<b-container fluid>
<b-row align-v="center" class="vh-100">
<b-col />
<b-col>
<LoginForm />
</b-col>
<b-col />
</b-row>
<b-row />
</b-container>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
})
</script>
<style scoped>
</style>
<template>
<b-container>
<b-row>
<b-col lg="6">
<b-button-group size="lg" class="btn-group-justified">
<CreateAppBtn />
<b-button pill variant="warning" @click="purge">
purge
</b-button>
<b-button pill variant="info">
mirror
</b-button>
</b-button-group>
</b-col>
<b-col class="col-md-6" />
</b-row>
<b-row>
<b-col>
<AppList />
</b-col>
</b-row>
</b-container>
</template>
<script>
import VueCookies from 'vue-cookies-ts'
import Vue from 'vue'
Vue.use(VueCookies)
export default Vue.extend({
name: 'Manager',
data () {
return {
}
},
mounted () {
const token = this.$cookies.get('Token')
if (token == null) {
window.location.href = '/login'
return
}
this.$axios.defaults.headers.common.Authorization = `Bearer ${token}`
},
methods: {
purge () {
this.$axios.get('/release/api/admin/purge').then((response) => {
if (response.data.success === true) {
this.$bvToast.toast('purge ok', {
autoHideDelay: 1000,
title: 'ok'
})
} else {
this.$bvToast.toast(response.data.message, {
autoHideDelay: 1000,
title: 'error'
})
}
})
},
mirror () {
this.$axios.get('/release/api/admin/mirror').then((response) => {
if (response.data.success === true) {
this.$bvToast.toast('mirror ok', {
autoHideDelay: 1000,
title: 'ok'
})
} else {
this.$bvToast.toast(response.data.message, {
autoHideDelay: 1000,
title: 'error'
})
}
})
}
}
})
</script>
<style scoped>
</style>
<template>
<b-container>
<b-form @submit="onSubmit">
<b-form-group
id="input-group-1"
label="version:"
label-for="input-1"
>
<b-form-input
id="input-1"
v-model="form.version"
type="text"
placeholder="Enter version"
required
/>
</b-form-group>
<b-form-group id="input-group-2" label="platform:" label-for="input-2">
<b-form-select
id="input-2"
v-model="form.platform"
placeholder="Enter name"
:options="platforms"
required
/>
</b-form-group>
<b-form-group id="input-group-3" label="locale:" label-for="input-3">
<b-form-select
id="input-3"
v-model="form.locale"
:options="locales"
required
/>
</b-form-group>
<b-form-group id="input-group-3" label="file:" label-for="input-4">
<b-form-file
id="input-4"
v-model="form.file"
:state="Boolean(form.file)"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
/>
</b-form-group>
<b-button type="submit" variant="primary">
Submit
</b-button>
</b-form>
</b-container>
</template>
<script>
import Vue from 'vue'
import VueCookies from 'vue-cookies-ts'
Vue.use(VueCookies)
export default {
name: 'Id',
data () {
return {
version: [],
form: {
version: '',
arch: '',
platform: '',
locale: '',
file: null
},
platforms: ['generic', 'linux', 'darwin', 'win32'],
locales: ['generic', 'zh-CN', 'en-US', 'ja-JP', 'ko-KR', 'pt-BR', 'zh-HK', 'zh-TW']
}
},
mounted () {
const token = this.$cookies.get('Token')
if (token == null) {
window.location.href = '/login'
return
}
this.$axios.defaults.headers.common.Authorization = `Bearer ${token}`
},
methods: {
onSubmit (event) {
event.preventDefault()
const formData = new FormData()
formData.append('file', this.form.file)
this.$axios.post(`/release/api/build/${this.$route.params.id}/${this.form.version}?platform=${this.form.platform}&locale=${this.form.locale}`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((response) => {
if (response.data.success === true) {
// this.json = JSON.stringify(response.data.data[0].appData).replace(/"([^"]+)":/g, '$1:')
this.$bvToast.toast('upload ok', {
autoHideDelay: 1000,
title: 'ok'
})
} else {
this.$bvToast.toast('req error', {
autoHideDelay: 1000,
title: 'error'
})
}
})
}
}
}
</script>
<style scoped>
</style>
# STORE
**This directory is not required, you can delete it if you don't want to use it.**
This directory contains your Vuex Store files.
Vuex Store option is implemented in the Nuxt.js framework.
Creating a file in this directory automatically activates the option in the framework.
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).
import { mount } from '@vue/test-utils'
import NuxtLogo from '@/components/NuxtLogo.vue'
describe('NuxtLogo', () => {
test('is a Vue instance', () => {
const wrapper = mount(NuxtLogo)
expect(wrapper.vm).toBeTruthy()
})
})
{
"compilerOptions": {
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "Node",
"lib": [
"ESNext",
"ESNext.AsyncIterable",
"DOM"
],
"esModuleInterop": true,
"allowJs": true,
"sourceMap": true,
"strict": true,
"noEmit": true,
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"~/*": [
"./*"
],
"@/*": [
"./*"
]
},
"types": [
"@nuxt/types",
"@nuxtjs/axios",
"@types/node"
]
},
"exclude": [
"node_modules",
".nuxt",
"dist"
]
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment