├── public
├── favicon.ico
├── img
│ ├── app.png
│ ├── logo.png
│ ├── login_bg.jpg
│ ├── download_pattern_left.png
│ └── download_pattern_right.png
├── config.js
└── index.html
├── babel.config.js
├── src
├── plugins
│ ├── element.js
│ ├── myPlugin.js
│ └── http
│ │ ├── http.js
│ │ └── axios.js
├── App.vue
├── style
│ ├── variables.scss
│ └── main.scss
├── store
│ └── store.js
├── main.js
├── views
│ ├── main
│ │ ├── Main.vue
│ │ ├── HeadBar.vue
│ │ └── Login.vue
│ ├── appDetail
│ │ ├── AppVersionEdit.vue
│ │ ├── AppVersions.vue
│ │ └── Preview.vue
│ └── appList
│ │ ├── AppUploadDialog.vue
│ │ └── AppList.vue
├── util
│ ├── loginUtil.js
│ └── constant.js
├── router
│ └── router.js
└── components
│ ├── VmSelectInput.vue
│ ├── VmSearch.vue
│ └── VmTable.vue
├── .npmrc
├── alias.config.js
├── .gitignore
├── vue.config.js
├── Dockerfile
├── nginx.conf
├── readme.md
└── package.json
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liu-xinhui/appPublishFront/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liu-xinhui/appPublishFront/HEAD/public/img/app.png
--------------------------------------------------------------------------------
/public/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liu-xinhui/appPublishFront/HEAD/public/img/logo.png
--------------------------------------------------------------------------------
/public/img/login_bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liu-xinhui/appPublishFront/HEAD/public/img/login_bg.jpg
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | "@vue/cli-plugin-babel/preset",
4 | ],
5 | };
6 |
--------------------------------------------------------------------------------
/src/plugins/element.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Element from "element-ui";
3 |
4 | Vue.use(Element, {size: "medium"});
5 |
--------------------------------------------------------------------------------
/public/img/download_pattern_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liu-xinhui/appPublishFront/HEAD/public/img/download_pattern_left.png
--------------------------------------------------------------------------------
/public/img/download_pattern_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liu-xinhui/appPublishFront/HEAD/public/img/download_pattern_right.png
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
2 | sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
3 | registry=https://registry.npm.taobao.org
4 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/src/style/variables.scss:
--------------------------------------------------------------------------------
1 | $header-height: 82px;
2 | $color-primary: #F8BA0B;
3 | $border-color: #E6E6E6;
4 |
5 | @mixin gravityCenter {
6 | display: flex;
7 | align-items: center;
8 | justify-content: center;
9 | }
10 |
--------------------------------------------------------------------------------
/src/store/store.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 |
3 | export let store = Vue.observable(
4 | {
5 | breadcrumbs: [],
6 | });
7 |
8 | export let mutations = {
9 | setBreadcrumbs(breadcrumbs) {
10 | store.breadcrumbs = breadcrumbs;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/alias.config.js:
--------------------------------------------------------------------------------
1 | /*此文件未使用,只是为了让idea可以识别实际位置*/
2 | const path = require("path");
3 |
4 | function resolve(dir) {
5 | return path.join(__dirname, dir);
6 | }
7 |
8 | module.exports = {
9 | resolve: {
10 | alias: {
11 | "@": resolve("src"),
12 | },
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 | *.iml
24 | *.ipr
25 | *.iws
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 | import router from "@/router/router";
4 | import "./plugins/element.js";
5 | import "./plugins/myPlugin.js";
6 | import "normalize.css";
7 | import "./style/main.scss";
8 |
9 | Vue.config.productionTip = false;
10 |
11 | new Vue({
12 | router,
13 | render: h => h(App),
14 | }).$mount("#app");
15 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | productionSourceMap: false,
3 | devServer: {
4 | port: 8011,
5 | },
6 | chainWebpack: config => {
7 | config
8 | .plugin("html")
9 | .tap(args => {
10 | args[0].title = "应用发布";
11 | return args;
12 | });
13 | // 用cdn方式引入
14 | config.externals({
15 | "vue": "Vue",
16 | "vue-router": "VueRouter",
17 | "element-ui": "ELEMENT",
18 | });
19 | },
20 | };
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.17.3-alpine
2 |
3 | MAINTAINER liunewshine@qq.com
4 |
5 | ENV TZ=Asia/Shanghai
6 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && mkdir -p /yanglaojin
7 |
8 | WORKDIR /yanglaojin
9 |
10 | ADD /dist/ /usr/share/nginx/html/
11 | # 自定义nginx配置文件,启用gzip
12 | ADD /nginx.conf /etc/nginx/nginx.conf
13 |
14 | ENV env "test"
15 |
16 | CMD sed -i "s/vueEnv.active/\"${env}\"/g" /usr/share/nginx/html/config.js && nginx -g 'daemon off;'
17 |
--------------------------------------------------------------------------------
/src/plugins/myPlugin.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import axios from "./http/axios";
3 | import http from "./http/http";
4 | import {Message} from "element-ui";
5 |
6 | Plugin.install = function(Vue) {
7 | // 网络请求
8 | Vue.prototype.$http = http;
9 | Vue.prototype.$axios = axios;
10 | //全局异常处理
11 | Vue.config.errorHandler = function(err, vm, info) {
12 | console.error(err, vm, info);
13 | Message.error(err);
14 | };
15 | };
16 | Vue.use(Plugin);
17 |
18 | export default Plugin;
19 |
--------------------------------------------------------------------------------
/src/style/main.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
3 | color: #9b9b9b;
4 | }
5 |
6 | /*定义滚动条宽高及背景,宽高分别对应横竖滚动条的尺寸*/
7 | ::-webkit-scrollbar {
8 | background-color: white;
9 | height: 13px;
10 | width: 13px;
11 | }
12 |
13 | /*定义滚动条的轨道,内阴影及圆角*/
14 | ::-webkit-scrollbar-track {
15 | background-color: #f5f5f5;
16 | }
17 |
18 | /*定义滑块,内阴影及圆角*/
19 | ::-webkit-scrollbar-thumb {
20 | background-color: #ccc;
21 | }
--------------------------------------------------------------------------------
/public/config.js:
--------------------------------------------------------------------------------
1 | /*全局配置文件,url类型的必须以"/"结尾*/
2 | var vueEnv = {
3 | //当前激活的环境
4 | active: "dev",
5 | //开发环境
6 | dev: {
7 | serverUrl: "http://127.0.0.1:8060/api/",
8 | },
9 | test: {
10 | serverUrl: "http://118.25.44.86:8556/api/",
11 | },
12 | prod: {
13 | serverUrl: "/api/",
14 | },
15 | };
16 |
17 | switch (vueEnv.active) {
18 | case "dev":
19 | window.config = vueEnv.dev;
20 | break;
21 | case "test":
22 | window.config = vueEnv.test;
23 | break;
24 | default:
25 | window.config = vueEnv.prod;
26 | break;
27 | }
--------------------------------------------------------------------------------
/src/views/main/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
35 |
--------------------------------------------------------------------------------
/src/util/loginUtil.js:
--------------------------------------------------------------------------------
1 | const USER_INFO = "hold_user_info";
2 | const storage = window.localStorage;
3 | let userInfo = null;
4 | export default {
5 | login(obj) {
6 | userInfo = obj;
7 | storage.setItem(USER_INFO, JSON.stringify(obj));
8 | },
9 | logout() {
10 | userInfo = null;
11 | storage.clear();
12 | },
13 | isLogin() {
14 | return !!this.getToken();
15 | },
16 | getUserInfo() {
17 | try {
18 | if (!userInfo) {
19 | userInfo = JSON.parse(storage.getItem(USER_INFO));
20 | }
21 | } catch (err) {
22 | console.log(err);
23 | }
24 | return userInfo || {};
25 | },
26 | getToken() {
27 | return this.getUserInfo().token;
28 | },
29 | getUsername() {
30 | return this.getUserInfo().username;
31 | },
32 | };
33 |
--------------------------------------------------------------------------------
/src/util/constant.js:
--------------------------------------------------------------------------------
1 | //garage类型
2 | const capStatus = ["0:无效", "1:有效"];
3 |
4 | let exportObj = {
5 | capStatus,
6 | };
7 |
8 | //------------------------------以下部分请勿改动------------------------------
9 | //转化为object和options
10 | //$options用于获取el-select可用的格式,$object用于根据key取中文描述
11 | for (let key in exportObj) {
12 | let value = exportObj[key];
13 | if (Array.isArray(value)) {
14 | let options = [];
15 | let object = {};
16 | value.forEach(item => {
17 | let itemArr = item.split(":");
18 | let option = {
19 | value: itemArr[0],
20 | label: itemArr[1],
21 | };
22 | object[option.value] = option.label;
23 | options.push(option);
24 | });
25 | value.$options = options;
26 | value.$object = object;
27 | }
28 | }
29 | export default exportObj;
30 |
--------------------------------------------------------------------------------
/src/router/router.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter from "vue-router";
3 |
4 | Vue.use(VueRouter);
5 |
6 | const routes = [
7 | {
8 | path: "/",
9 | meta: {title: "Main中展示的组件"},
10 | component: () => import("@/views/main/Main"),
11 | children: [
12 | {path: "/", meta: {title: "首页"}, component: () => import("@/views/appList/AppList")},
13 | {path: "apps/:id", meta: {title: "应用动态"}, component: () => import("@/views/appDetail/AppVersions")},
14 | ],
15 | },
16 | {path: "/login", meta: {title: "登录"}, component: () => import("@/views/main/Login")},
17 | {path: "/:shortCode", meta: {title: "下载页"}, component: () => import("@/views/appDetail/Preview")},
18 | ];
19 |
20 | const router = new VueRouter({
21 | mode: "history",
22 | routes,
23 | });
24 |
25 | export const toLogin = () => {
26 | router.push({
27 | path: "/login",
28 | });
29 | };
30 |
31 | export default router;
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 |
2 | user nginx;
3 | worker_processes auto;
4 |
5 | error_log /var/log/nginx/error.log warn;
6 | pid /var/run/nginx.pid;
7 |
8 |
9 | events {
10 | worker_connections 1024;
11 | }
12 |
13 |
14 | http {
15 | include /etc/nginx/mime.types;
16 | default_type application/octet-stream;
17 |
18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19 | '$status $body_bytes_sent "$http_referer" '
20 | '"$http_user_agent" "$http_x_forwarded_for"';
21 |
22 | access_log /var/log/nginx/access.log main;
23 |
24 | sendfile on;
25 | #tcp_nopush on;
26 |
27 | keepalive_timeout 65;
28 |
29 | gzip on;
30 | gzip_vary on;
31 | gzip_proxied any;
32 | gzip_comp_level 6;
33 | gzip_buffers 16 8k;
34 | gzip_http_version 1.1;
35 | gzip_min_length 256;
36 | gzip_types text/plain text/css application/json application/javascript;
37 |
38 | include /etc/nginx/conf.d/*.conf;
39 | }
40 |
--------------------------------------------------------------------------------
/src/plugins/http/http.js:
--------------------------------------------------------------------------------
1 | import axios from "./axios";
2 |
3 | export default {
4 | /**
5 | * Get方法获取数据
6 | * get(String url,Object params) 示例get('users',{pageNum:1})
7 | */
8 | get: function(url, params) {
9 | return axios({
10 | url: url,
11 | method: "get",
12 | params: params,
13 | });
14 | },
15 | put: function(url, data, params) {
16 | return axios({
17 | url: url,
18 | method: "put",
19 | data: data,
20 | params: params,
21 | });
22 | },
23 | post: function(url, data, params) {
24 | return axios({
25 | url: url,
26 | method: "post",
27 | data: data,
28 | params: params,
29 | });
30 | },
31 | // 删除,示例delete('users',10)
32 | delete: (url, id) => {
33 | return axios({
34 | url: id ? (url + "/" + id) : url,
35 | method: "delete",
36 | });
37 | },
38 | //保存,当id大于0时为修改采用put,其他为新增采用post
39 | save: (url, data) => {
40 | return axios({
41 | url: url,
42 | method: !data.id || data.id === 0 ? "post" : "put",
43 | data: data,
44 | });
45 | },
46 | };
47 |
--------------------------------------------------------------------------------
/src/components/VmSelectInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
35 |
36 |
50 |
--------------------------------------------------------------------------------
/src/components/VmSearch.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{label}}
6 |
7 |
8 |
9 |
10 |
11 |
39 |
40 |
62 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## 介绍
2 |
3 | 项目是 `vue` 开发的类似`fir.im`和`蒲公英`的企业 APP 分发平台,提供android app上传功能,以及ios和android二维码合并功能。用过可直接通过微信、浏览器、QQ等扫码下载app。
4 |
5 | 此项目为前后端分离,后端采用spring boot实现,请移步https://github.com/liu-xinhui/appPublish
6 |
7 | **为加快应用下载页访问速度,本项目已启用gzip,vue和element ui相关js采用cdn加载,路由懒加载等优化,和普通多页应用无异**
8 |
9 | ## 效果
10 |
11 | 样式完全参考http://fir.im
12 |
13 | 本项目预览地址http://118.25.44.86:8556/
14 |
15 | 账号:admin
16 |
17 | 密码:123456
18 |
19 | ## 部署
20 |
21 | 本项目已经打包成docker镜像并上传到腾讯云的镜像仓库,可直接pull镜像进行部署,也可拉取代码做适应性修改后重新打包
22 |
23 | ```dockerfile
24 | #拉取镜像
25 | docker pull ccr.ccs.tencentyun.com/liuxh/app-publish
26 |
27 | #运行
28 | docker run -itd -p 8060:8060 -v /webapps/appPublish:/my-app/ap --restart=always --name app-publish --env SPRING_PROFILES_ACTIVE=prod ccr.ccs.tencentyun.com/liuxh/app-publish
29 | ```
30 |
31 | - 项目内部端口为`8060`
32 | - 容器内部数据存储位置`/my-app/ap`,需要做`docker volume`防止容器删除后数据丢失`-v /webapps/appPublish:/my-app/ap`
33 | - 需要设置项目运行环境为`prod`,`--env SPRING_PROFILES_ACTIVE=prod`
34 |
35 | ## 技术栈
36 |
37 | - `vue cli4`
38 | - `vue 2.6.11`
39 | - `spring boot 2.3.2.RELEASE`
40 | - `h2数据库` 嵌入式数据库,性能好,部署方便,可与mysql无缝切换
41 | - `mybatis-plus 3.3.2`
42 |
43 | ## 截图
44 |
45 | 
46 | 
47 | 
48 | 
49 | 
--------------------------------------------------------------------------------
/src/plugins/http/axios.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import auth from "@/util/loginUtil";
3 | import {toLogin} from "@/router/router";
4 | import {Notification} from "element-ui";
5 |
6 | // axios 配置
7 | axios.defaults.timeout = 40000;
8 | axios.defaults.baseURL = window.config.serverUrl;
9 | // http request 拦截器
10 | axios.interceptors.request.use(
11 | config => {
12 | config.headers["Authorization"] = auth.getToken();
13 | return config;
14 | },
15 | err => {
16 | return Promise.reject(err);
17 | },
18 | );
19 |
20 | // http response 拦截器
21 | axios.interceptors.response.use(
22 | response => {
23 | return response;
24 | },
25 | error => {
26 | console.log("-------------接口请求错误信息start-------------");
27 | console.log(error);
28 | if (error.response) {
29 | // The request was made and the server responded with a status code
30 | // that falls out of the range of 2xx
31 | console.log(error.response.data, error.response.status, error.response.headers);
32 | Notification.error({title: "提示", message: error.response.data.message});
33 | if (error.response.status === 401) {
34 | toLogin();
35 | }
36 | } else if (error.request) {
37 | // The request was made but no response was received
38 | // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
39 | // http.ClientRequest in node.js
40 | console.log(error.request);
41 | Notification.error({title: "提示", message: "连接服务器失败"});
42 | } else {
43 | // Something happened in setting up the request that triggered an Error
44 | console.log("Error", error.message);
45 | Notification.error({title: "提示", message: "请求服务器出错"});
46 | }
47 | console.log("-------------接口请求错误信息end-------------");
48 | return Promise.reject(error);
49 | },
50 | );
51 |
52 | export default axios;
53 |
--------------------------------------------------------------------------------
/src/views/appDetail/AppVersionEdit.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
14 |
15 |
16 |
17 |
18 | 取消
19 | 保存
20 |
21 |
22 |
23 |
24 |
64 |
65 |
67 |
68 |
--------------------------------------------------------------------------------
/src/views/main/HeadBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
56 |
57 |
124 |
--------------------------------------------------------------------------------
/src/views/main/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 欢迎访问应用发布平台
7 |
8 |
9 |
10 |
11 | 账号
12 |
13 |
14 |
15 |
16 | 密码
17 |
18 |
19 |
25 | 登录
26 |
27 |
28 |
29 |
30 |
31 | © 2020-{{new Date().getFullYear()}} 版权所有
32 |
沪ICP备13031758号
33 |
34 |
35 |
36 |
37 |
75 |
76 |
103 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | <%= htmlWebpackPlugin.options.title %>
15 |
73 |
74 |
75 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yanglaojin",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "@chenfengyuan/vue-qrcode": "^1.0.2",
12 | "app-info-parser": "^0.3.10",
13 | "axios": "^0.19.2",
14 | "core-js": "^3.6.5",
15 | "normalize.css": "^8.0.1",
16 | "vue": "^2.6.11"
17 | },
18 | "devDependencies": {
19 | "@vue/cli-plugin-babel": "~4.4.0",
20 | "@vue/cli-plugin-eslint": "~4.4.0",
21 | "@vue/cli-plugin-router": "~4.4.0",
22 | "@vue/cli-service": "~4.4.0",
23 | "babel-eslint": "^10.1.0",
24 | "eslint": "^6.7.2",
25 | "eslint-plugin-vue": "^6.2.2",
26 | "lint-staged": "^9.5.0",
27 | "node-sass": "^4.12.0",
28 | "sass-loader": "^8.0.2",
29 | "vue-template-compiler": "^2.6.11"
30 | },
31 | "eslintConfig": {
32 | "root": true,
33 | "env": {
34 | "node": true
35 | },
36 | "extends": [
37 | "plugin:vue/essential",
38 | "eslint:recommended"
39 | ],
40 | "parserOptions": {
41 | "parser": "babel-eslint"
42 | },
43 | "rules": {
44 | "no-console": "off",
45 | "no-irregular-whitespace": "off",
46 | "quotes": [
47 | "error",
48 | "double"
49 | ],
50 | "semi": [
51 | "error",
52 | "always"
53 | ],
54 | "space-in-parens": [
55 | "warn",
56 | "never"
57 | ],
58 | "space-before-function-paren": [
59 | "warn",
60 | "never"
61 | ],
62 | "space-before-blocks": [
63 | "warn",
64 | "always"
65 | ],
66 | "vue/attribute-hyphenation": "warn",
67 | "vue/html-closing-bracket-spacing": [
68 | "error",
69 | {
70 | "selfClosingTag": "never"
71 | }
72 | ],
73 | "vue/html-end-tags": "error",
74 | "vue/html-indent": [
75 | "warn",
76 | 2,
77 | {
78 | "attribute": 2,
79 | "baseIndent": 1,
80 | "closeBracket": 0,
81 | "alignAttributesVertically": true,
82 | "ignores": []
83 | }
84 | ],
85 | "vue/script-indent": [
86 | "warn",
87 | 2,
88 | {
89 | "baseIndent": 1,
90 | "switchCase": 1,
91 | "ignores": []
92 | }
93 | ],
94 | "vue/html-quotes": "error",
95 | "vue/html-self-closing": "error",
96 | "vue/max-attributes-per-line": [
97 | "warn",
98 | {
99 | "singleline": 4,
100 | "multiline": {
101 | "max": 1,
102 | "allowFirstLine": false
103 | }
104 | }
105 | ],
106 | "vue/multiline-html-element-content-newline": "warn",
107 | "vue/mustache-interpolation-spacing": [
108 | "error",
109 | "never"
110 | ],
111 | "vue/name-property-casing": "error",
112 | "vue/no-multi-spaces": "warn",
113 | "vue/no-spaces-around-equal-signs-in-attribute": "warn",
114 | "vue/no-template-shadow": "warn",
115 | "vue/prop-name-casing": "error",
116 | "vue/require-prop-types": "error",
117 | "vue/v-bind-style": "warn",
118 | "vue/v-on-style": "warn",
119 | "vue/attributes-order": "warn",
120 | "vue/no-confusing-v-for-v-if": "error",
121 | "vue/no-v-html": "off",
122 | "vue/order-in-components": "warn",
123 | "vue/this-in-template": "error",
124 | "vue/camelcase": "error",
125 | "comma-dangle": [
126 | "error",
127 | "always-multiline"
128 | ],
129 | "vue/component-name-in-template-casing": [
130 | "warn",
131 | "kebab-case"
132 | ],
133 | "vue/eqeqeq": "warn",
134 | "vue/match-component-file-name": "error"
135 | }
136 | },
137 | "browserslist": [
138 | "> 1%",
139 | "last 2 versions",
140 | "not dead"
141 | ],
142 | "lint-staged": {
143 | "*.{js,jsx,vue}": [
144 | "vue-cli-service lint",
145 | "git add"
146 | ]
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/views/appList/AppUploadDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
17 |
18 |
![图标]()
23 |
24 | {{model.versionName}} (Build {{model.versionCode}})
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
114 |
115 |
149 |
--------------------------------------------------------------------------------
/src/views/appList/AppList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
将文件拖到此处,或点击上传
20 |
21 |
22 |
23 |
![图标]()
30 |
{{item.name}}
31 |
32 |
33 | | 短链接: |
34 | {{getUrl(item)}} |
35 |
36 |
37 | | PackageName: |
38 | {{item.packageName}} |
39 |
40 |
41 | | 最新版本: |
42 | {{item.currentVersion.versionName}} (Build {{item.currentVersion.versionCode}}) |
43 |
44 |
45 |
46 | 编辑
47 | 预览
48 |
49 |
50 |
54 |
55 |
56 |
57 |
125 |
126 |
215 |
--------------------------------------------------------------------------------
/src/components/VmTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
18 | 重置
19 |
20 |
26 | 查询
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
46 |
50 |
51 |
52 | 加载失败,点击重新获取
53 | 暂无数据
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
71 |
72 |
73 |
74 |
75 |
76 |
189 |
190 |
229 |
--------------------------------------------------------------------------------
/src/views/appDetail/AppVersions.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![图标]()
12 |
13 | {{url}}
14 |
15 | 包名
16 | {{appInfo.packageName}}
17 |
18 |
19 | 下载次数
20 | {{appInfo.downloadCount}}
21 |
22 |
23 |
34 |
40 | 预览
41 |
42 |
43 |
44 |
49 |
50 |
51 |
57 |
58 |
{{item.createTime}}
59 |
{{item.changeLog}}
60 |
61 |
62 |
63 | {{(item.size/1024).toFixed(2)}} MB
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {{host}}
77 |
78 |
79 |
80 |
81 |
82 | 保存
83 |
84 |
85 |
86 |
87 |
88 | 保存
89 |
90 |
91 |
92 |
93 |
94 |
95 |
195 |
196 |
--------------------------------------------------------------------------------
/src/views/appDetail/Preview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |

5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 | {{appInfo.name}}
31 |
32 |
33 |
34 | 扫描二维码下载
或用手机浏览器输入这个网址: {{url}}
35 |
36 |
37 |
38 | {{appInfo.currentVersion.versionName+"(Build " +appInfo.currentVersion.versionCode+")-"}}
39 | {{(appInfo.currentVersion.size/1024).toFixed(2)}} MB
40 |
41 |
更新于: {{appInfo.currentVersion.createTime}}
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | 请点击右上角
选择"在浏览器打开"
53 |
54 |
57 |
58 |
59 |
60 |
154 |
3325 |
--------------------------------------------------------------------------------