From 9d3a8751823c61a0a6751c48c1178b5581a871dd Mon Sep 17 00:00:00 2001
From: wzz <280348905@qq.com>
Date: Wed, 21 Jul 2021 12:43:42 +0800
Subject: [PATCH] =?UTF-8?q?update=20=E6=A8=A1=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.babelrc | 4 +
.env | 14 +
.env.production | 2 +
.eslintrc.js | 26 +
.gitignore | 24 +
babel.config.js | 3 +
package.json | 73 +++
public/config/config.js | 3 +
public/index.html | 33 ++
src/App.vue | 46 ++
src/api/index.js | 17 +
src/api/modules/auth/index.js | 19 +
src/api/modules/mobile/index.js | 94 ++++
src/api/modules/pc/index.js | 39 ++
src/api/service.js | 144 +++++
src/api/tools.js | 112 ++++
src/libs/util.db.js | 91 ++++
src/libs/util.filter.js | 120 +++++
src/libs/util.js | 11 +
src/libs/util.message.js | 32 ++
src/libs/util.token.js | 53 ++
src/libs/util.tool.js | 35 ++
src/libs/util.url.js | 12 +
src/main.js | 54 ++
src/plugin/index.js | 9 +
src/router/index.js | 84 +++
src/router/modules/mobile/index.js | 38 ++
src/router/modules/pc/index.js | 12 +
src/router/modules/system/index.js | 17 +
src/store/index.js | 29 ++
src/store/modules/manage/index.js | 16 +
src/store/modules/manage/modules/question.js | 170 ++++++
src/store/modules/manage/modules/register.js | 78 +++
.../modules/manage/modules/statistics.js | 107 ++++
src/store/modules/plugin/index.js | 16 +
src/store/modules/plugin/modules/baseinfo.js | 59 +++
src/store/modules/plugin/modules/dialog.js | 27 +
src/store/modules/plugin/modules/loading.js | 39 ++
src/store/modules/plugin/modules/page.js | 28 +
src/store/modules/plugin/modules/show.js | 29 ++
src/store/modules/plugin/modules/switch.js | 14 +
src/store/modules/plugin/modules/tools.js | 58 +++
src/store/modules/plugin/modules/wechat.js | 313 +++++++++++
src/styles/_var.scss | 43 ++
src/styles/all.scss | 490 ++++++++++++++++++
src/styles/common.scss | 72 +++
src/styles/fixed/fixed_element.scss | 0
src/styles/mixin.scss | 199 +++++++
src/styles/settings.scss | 18 +
src/views/index.vue | 12 +
src/views/redirect/index.vue | 24 +
vue.config.js | 132 +++++
52 files changed, 3194 insertions(+)
create mode 100644 .babelrc
create mode 100644 .env
create mode 100644 .env.production
create mode 100644 .eslintrc.js
create mode 100644 .gitignore
create mode 100644 babel.config.js
create mode 100644 package.json
create mode 100644 public/config/config.js
create mode 100644 public/index.html
create mode 100644 src/App.vue
create mode 100644 src/api/index.js
create mode 100644 src/api/modules/auth/index.js
create mode 100644 src/api/modules/mobile/index.js
create mode 100644 src/api/modules/pc/index.js
create mode 100644 src/api/service.js
create mode 100644 src/api/tools.js
create mode 100644 src/libs/util.db.js
create mode 100644 src/libs/util.filter.js
create mode 100644 src/libs/util.js
create mode 100644 src/libs/util.message.js
create mode 100644 src/libs/util.token.js
create mode 100644 src/libs/util.tool.js
create mode 100644 src/libs/util.url.js
create mode 100644 src/main.js
create mode 100644 src/plugin/index.js
create mode 100644 src/router/index.js
create mode 100644 src/router/modules/mobile/index.js
create mode 100644 src/router/modules/pc/index.js
create mode 100644 src/router/modules/system/index.js
create mode 100644 src/store/index.js
create mode 100644 src/store/modules/manage/index.js
create mode 100644 src/store/modules/manage/modules/question.js
create mode 100644 src/store/modules/manage/modules/register.js
create mode 100644 src/store/modules/manage/modules/statistics.js
create mode 100644 src/store/modules/plugin/index.js
create mode 100644 src/store/modules/plugin/modules/baseinfo.js
create mode 100644 src/store/modules/plugin/modules/dialog.js
create mode 100644 src/store/modules/plugin/modules/loading.js
create mode 100644 src/store/modules/plugin/modules/page.js
create mode 100644 src/store/modules/plugin/modules/show.js
create mode 100644 src/store/modules/plugin/modules/switch.js
create mode 100644 src/store/modules/plugin/modules/tools.js
create mode 100644 src/store/modules/plugin/modules/wechat.js
create mode 100644 src/styles/_var.scss
create mode 100644 src/styles/all.scss
create mode 100644 src/styles/common.scss
create mode 100644 src/styles/fixed/fixed_element.scss
create mode 100644 src/styles/mixin.scss
create mode 100644 src/styles/settings.scss
create mode 100644 src/views/index.vue
create mode 100644 src/views/redirect/index.vue
create mode 100644 vue.config.js
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..31a358d
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": [["@babel/preset-env", { "modules": false }]],
+ "plugins": []
+}
diff --git a/.env b/.env
new file mode 100644
index 0000000..9d3f435
--- /dev/null
+++ b/.env
@@ -0,0 +1,14 @@
+# 所有环境默认
+VUE_APP_VERSION=1.0.0
+
+# 页面 title 前缀
+VUE_APP_TITLE=管理平台
+
+# 部署路径
+VUE_APP_PUBLIC_PATH=/
+
+# 缓存前缀
+VUE_APP_LOCAL_CODE=admin
+
+
+
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,2 @@
+
+
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..dda2639
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,26 @@
+module.exports = {
+ root: true,
+ env: {
+ node: true,
+ },
+ extends: [
+ "plugin:vue/essential",
+ //关闭ESlint关键代码
+ // '@vue/standard'
+ ],
+ parserOptions: {
+ parser: "babel-eslint",
+ },
+ rules: {
+ //严格的检查缩进问题,不是报错,我们可以关闭这个检查规则,然后在终端输入npm run dev
+ indent: ["off", 2],
+ "vue/no-parsing-error": [2, { "x-invalid-end-tag": false }],
+ //使用eslint时,严格模式下,报错Missing space before function parentheses的问题,意思是在方法名和刮号之间需要有一格空格。
+ "space-before-function-paren": 0,
+ "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
+ "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
+ //关闭prettier
+ "prettier/prettier": "off",
+ "vue/no-use-v-if-with-v-for": "off",
+ },
+};
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..86936ae
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+.DS_Store
+node_modules
+/dist
+
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+package-lock.json
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..162a3ea
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ presets: ["@vue/cli-plugin-babel/preset"],
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2c4b018
--- /dev/null
+++ b/package.json
@@ -0,0 +1,73 @@
+{
+ "name": "antifraud",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "report": "vue-cli-service build --report",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "axios": "^0.21.1",
+ "core-js": "^3.12.1",
+ "dayjs": "^1.10.4",
+ "echarts": "^5.1.1",
+ "element-ui": "^2.15.1",
+ "lodash": "^4.17.21",
+ "lowdb": "^1.0.0",
+ "vant": "^2.12.18",
+ "vue": "^2.6.12",
+ "vue-json-excel": "^0.3.0",
+ "vue-mini-player": "^0.2.1",
+ "vue-router": "^3.5.1",
+ "vuex": "^3.6.2",
+ "vuex-persistedstate": "^4.0.0-beta.3",
+ "weixin-js-sdk": "^1.6.0",
+ "xlsx": "^0.16.9"
+ },
+ "devDependencies": {
+ "@vue/cli-plugin-babel": "^4.5.13",
+ "@vue/cli-plugin-eslint": "^4.5.13",
+ "@vue/cli-plugin-router": "^4.5.13",
+ "@vue/cli-plugin-vuex": "^4.5.13",
+ "@vue/cli-service": "^4.5.13",
+ "postcss-px2rem": "^0.3.0",
+ "amfe-flexible": "^2.2.1",
+ "babel-eslint": "^10.1.0",
+ "babel-plugin-component": "^1.1.1",
+ "babel-plugin-import": "^1.13.3",
+ "compression-webpack-plugin": "^5.0.2",
+ "eslint": "^6.8.0",
+ "eslint-plugin-prettier": "^3.4.0",
+ "eslint-plugin-vue": "^6.2.2",
+ "image-webpack-loader": "^7.0.1",
+ "node-sass": "^5.0.0",
+ "px2rem-loader": "^0.1.9",
+ "sass": "^1.32.12",
+ "sass-loader": "^10.2.0",
+ "vconsole": "^3.5.1",
+ "vue-template-compiler": "^2.6.12",
+ "vue-wxlogin": "^1.0.4",
+ "webpack-bundle-analyzer": "^4.4.2"
+ },
+ "eslintConfig": {
+ "root": true,
+ "env": {
+ "node": true
+ },
+ "extends": [
+ "plugin:vue/strongly-recommended",
+ "eslint:recommended",
+ "@vue/prettier"
+ ],
+ "parserOptions": {
+ "parser": "babel-eslint"
+ }
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not dead"
+ ]
+}
diff --git a/public/config/config.js b/public/config/config.js
new file mode 100644
index 0000000..5d75e1a
--- /dev/null
+++ b/public/config/config.js
@@ -0,0 +1,3 @@
+var config = {};
+
+config.API = "";
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..a3be31d
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ <%= VUE_APP_TITLE %>
+
+
+
+
+
+
+ <% if (process.env.NODE_ENV==='production' ) { %>
+ <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
+
+ <% } %>
+ <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
+
+ <% } %>
+ <% } %>
+
+
+
\ No newline at end of file
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..514d37e
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/api/index.js b/src/api/index.js
new file mode 100644
index 0000000..0099ebd
--- /dev/null
+++ b/src/api/index.js
@@ -0,0 +1,17 @@
+import { assign, map } from "lodash";
+import { service, request } from "./service";
+import * as tools from "./tools";
+
+const files = require.context("./modules", true, /\.js$/);
+const generators = files.keys().map((key) => files(key).default);
+
+export default assign(
+ {},
+ ...map(generators, (generator) =>
+ generator({
+ service,
+ request,
+ tools,
+ })
+ )
+);
diff --git a/src/api/modules/auth/index.js b/src/api/modules/auth/index.js
new file mode 100644
index 0000000..d7186ed
--- /dev/null
+++ b/src/api/modules/auth/index.js
@@ -0,0 +1,19 @@
+export default ({ request }) => ({
+ /**
+ * @params proj code appid
+ * @return proj code appid
+ */
+ authWx(data = {}) {
+ return request({
+ url: `/verification?proj=${data.proj}&code=${data.code}&appid=${data.appid}`,
+ method: "get",
+ });
+ },
+ loadConfigInfo(data = {}) {
+ return request({
+ url: "/usr/jsconfig",
+ method: "post",
+ data,
+ });
+ },
+});
diff --git a/src/api/modules/mobile/index.js b/src/api/modules/mobile/index.js
new file mode 100644
index 0000000..e6bb1e1
--- /dev/null
+++ b/src/api/modules/mobile/index.js
@@ -0,0 +1,94 @@
+export default ({ request }) => ({
+ /**
+ * @description 下载网格长
+ */
+ loadAdminPerson(data) {
+ return request({
+ url: `/usr/manager?id=${data.id}`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 获取辖区
+ */
+ loadAdminArea() {
+ return request({
+ url: `/org/jurisdiction`,
+ method: "get",
+ });
+ },
+
+ /**
+ * @description 随机获取视频url
+ */
+ loadVideoUrl() {
+ return request({
+ url: `/video/get`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 回答者注册
+ */
+ answererRegister(data = {}) {
+ return request({
+ url: `/usr/register`,
+ method: "post",
+ data,
+ });
+ },
+ /**
+ * @description 下载全部题目列表 已打乱
+ */
+ loadQuestionList() {
+ return request({
+ url: `/question/get`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 下载单题选项
+ * @params id
+ */
+ loadQuestionItem(data = {}) {
+ return request({
+ url: `/question/item/${data.id}`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 提交答案
+ * @params duration location answer
+ */
+ questionSubmit(data = {}) {
+ return request({
+ url: `/question/submit`,
+ method: "post",
+ data,
+ });
+ },
+ /**
+ * @description 计数
+ * @params duration location answer
+ */
+ videoPlayCount(data = {}) {
+ // let param;
+ // if (data.id !== "") {
+ // param = "?id=" + data.id;
+ // }
+ return request({
+ url: `/video/count`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 下载大奖信息
+ * @params id
+ */
+ loadNoticePrice(data = {}) {
+ return request({
+ url: `/project/notice`,
+ method: "get",
+ });
+ },
+});
diff --git a/src/api/modules/pc/index.js b/src/api/modules/pc/index.js
new file mode 100644
index 0000000..88a899e
--- /dev/null
+++ b/src/api/modules/pc/index.js
@@ -0,0 +1,39 @@
+export default ({ request }) => ({
+ /**
+ * @description 概述信息
+ */
+ loadSummary() {
+ return request({
+ url: `/admin/summary`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 考核信息
+ */
+ loadAssessment() {
+ return request({
+ url: `/admin/assessment`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 概述信息
+ 辖区id 秒级时间戳
+ */
+ loadAnalysis(data) {
+ return request({
+ url: `/admin/analysis?id=${data.id}&s=${data.start}&e=${data.end}`,
+ method: "get",
+ });
+ },
+ /**
+ * @description 奖励信息
+ */
+ loadFee() {
+ return request({
+ url: `/admin/fee`,
+ method: "get",
+ });
+ },
+});
diff --git a/src/api/service.js b/src/api/service.js
new file mode 100644
index 0000000..ef7b3f3
--- /dev/null
+++ b/src/api/service.js
@@ -0,0 +1,144 @@
+import axios from "axios";
+import { get, set } from "lodash";
+import { dbGet } from "@/libs/util.db";
+import { removeToken } from "@/libs/util.token";
+
+import { errorLog, errorCreate, errorMsgCreate, loadingMsgCreate } from "./tools";
+import router from "@/router/index";
+import msg from "@/libs/util.message";
+import { Toast } from "vant";
+import store from "../store";
+
+const serviceConfigApi = config.API;
+let toast;
+
+/**
+ * @description 创建请求实例
+ */
+function createService() {
+ // 创建一个 axios 实例
+ const service = axios.create();
+ // 请求拦截
+ service.interceptors.request.use(
+ (config) => {
+ const token = dbGet({ path: "token.value" });
+ set(config, "headers.access-token", token);
+ set(config, "toast", msg.loading(""));
+ return config;
+ },
+ (error) => {
+ // 发送失败
+ console.log(error);
+ return Promise.reject(error);
+ }
+ );
+
+ // 响应拦截
+ service.interceptors.response.use(
+ (response) => {
+ // dataAxios 是 axios 返回数据中的 data
+ const dataAxios = response.data;
+ // 这个状态码是和后端约定的
+ const { code } = dataAxios;
+ //去掉 loading
+ response.config.toast.clear();
+ // 根据 code 进行判断
+ if (code === undefined) {
+ // 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本
+ return dataAxios;
+ } else {
+ // 有 code 代表这是一个后端接口 可以进行进一步的判断
+
+ switch (code) {
+ case 0:
+ return dataAxios.data;
+ case 1:
+ removeToken();
+ errorMsgCreate(`${dataAxios.msg}`);
+ location.reload();
+ return false;
+ case 2:
+ errorMsgCreate(`${dataAxios.msg}`);
+ return false;
+ default:
+ // 不是正确的 code
+ errorCreate(`${dataAxios.msg}: ${response.config.url}`);
+ break;
+ }
+ }
+ },
+ (error) => {
+ // console.log(error);
+ const status = get(error, "response.status");
+ let toash = get(error, "response.config.toast");
+ toash.clear();
+
+ switch (status) {
+ case 400:
+ error.message = "请求错误";
+ break;
+ case 401:
+ error.message = "未授权,请登录";
+ break;
+ case 403:
+ error.message = "拒绝访问";
+ break;
+ case 404:
+ error.message = `请求地址出错: ${error.response.config.url}`;
+ break;
+ case 408:
+ error.message = "请求超时";
+ break;
+ case 500:
+ error.message = "服务器内部错误";
+ break;
+ case 501:
+ error.message = "服务未实现";
+ break;
+ case 502:
+ error.message = "网关错误";
+ break;
+ case 503:
+ error.message = "服务不可用";
+ break;
+ case 504:
+ error.message = "网关超时";
+ break;
+ case 505:
+ error.message = "HTTP版本不受支持";
+ break;
+ default:
+ break;
+ }
+ errorLog(error);
+ Toast.clear();
+ return Promise.reject(error);
+ }
+ );
+ return service;
+}
+
+/**
+ * @description 创建请求方法
+ * @param {Object} service axios 实例
+ */
+function createRequestFunction(service) {
+ return function(config) {
+ const token = dbGet({ path: "token.value" });
+ const configDefault = {
+ headers: {
+ "access-token": token,
+ "Content-Type": get(config, "headers.Content-Type", "application/json"),
+ },
+ timeout: 5000,
+ baseURL: process.env.NODE_ENV === "production" ? serviceConfigApi : "/apis",
+ data: {},
+ };
+ return service(Object.assign(configDefault, config));
+ };
+}
+//
+
+// 用于真实网络请求的实例和请求方法
+export const service = createService();
+export const request = createRequestFunction(service);
diff --git a/src/api/tools.js b/src/api/tools.js
new file mode 100644
index 0000000..1593d15
--- /dev/null
+++ b/src/api/tools.js
@@ -0,0 +1,112 @@
+import { Toast } from "vant";
+/**
+ * @description 安全地解析 json 字符串
+ * @param {String} jsonString 需要解析的 json 字符串
+ * @param {String} defaultValue 默认值
+ */
+export function parse(jsonString = "{}", defaultValue = {}) {
+ let result = defaultValue;
+ try {
+ result = JSON.parse(jsonString);
+ } catch (error) {
+ //console.log(error);
+ }
+ return result;
+}
+
+/**
+ * @description 接口请求返回
+ * @param {Any} data 返回值
+ * @param {String} msg 状态信息
+ * @param {Number} code 状态码
+ */
+export function response(data = {}, msg = "", code = 0) {
+ return [200, { code, msg, data }];
+}
+
+/**
+ * @description 接口请求返回 正确返回
+ * @param {Any} data 返回值
+ * @param {String} msg 状态信息
+ */
+export function responseSuccess(data = {}, msg = "成功") {
+ return response(data, msg);
+}
+
+/**
+ * @description 接口请求返回 错误返回
+ * @param {Any} data 返回值
+ * @param {String} msg 状态信息
+ * @param {Number} code 状态码
+ */
+export function responseError(data = {}, msg = "请求失败", code = 500) {
+ return response(data, msg, code);
+}
+
+/**
+ * @description 记录和显示错误
+ * @param {Error} error 错误对象
+ */
+let errorLogFlag = false;
+
+export function errorLog(error) {
+ // 打印到控制台
+ // if (errorLogFlag) return;
+
+ if (process.env.NODE_ENV === "development") {
+ //console.log(error);
+ }
+ // 显示提示
+ // errorLogFlag = true;
+
+ // Message.error({
+ // content: error.message,
+ // duration: 5,
+ // onClose: () => {
+ // errorLogFlag = false;
+ // },
+ // });
+}
+
+/**
+ * @description 创建一个错误
+ * @param {String} msg 错误信息
+ */
+export function errorCreate(msg) {
+ const error = new Error(msg);
+ errorLog(error);
+ throw error;
+}
+
+/**
+ * @description 创建一个错误弹窗
+ * @param {String} msg
+ */
+let msgFlag = false;
+export function errorMsgCreate(msg) {
+ // 显示提示
+ if (msgFlag) return;
+ msgFlag = true;
+ Toast.fail({
+ message: msg,
+ duration: 5000,
+ onClose: () => {
+ msgFlag = false;
+ },
+ });
+}
+
+let loadingFlag = false;
+export function loadingMsgCreate(msg) {
+ // 显示提示
+ if (loadingFlag) return;
+ loadingFlag = true;
+ Toast.loading({
+ message: msg,
+ duration: 5000,
+ forbidClick: true,
+ onClose: () => {
+ loadingFlag = false;
+ },
+ });
+}
diff --git a/src/libs/util.db.js b/src/libs/util.db.js
new file mode 100644
index 0000000..3adef5a
--- /dev/null
+++ b/src/libs/util.db.js
@@ -0,0 +1,91 @@
+import low from "lowdb";
+import LocalStorage from "lowdb/adapters/LocalStorage";
+import { cloneDeep } from "lodash";
+
+//console.log(`${process.env.VUE_APP_LOCAL_CODE}-${process.env.VUE_APP_VERSION}`);
+const adapter = new LocalStorage(`${process.env.VUE_APP_LOCAL_CODE}-${process.env.VUE_APP_VERSION}`);
+const db = low(adapter);
+
+db.defaults({
+ sys: {},
+ database: {},
+}).write();
+
+export default db;
+
+/**
+ * @description 检查路径是否存在 不存在的话初始化
+ * @param {Object} payload dbName {String} 数据库名称
+ * @param {Object} payload path {String} 路径
+ * @param {Object} payload user {Boolean} 区分用户
+ * @param {Object} payload validator {Function} 数据校验钩子 返回 true 表示验证通过
+ * @param {Object} payload defaultValue {*} 初始化默认值
+ * @returns {String} 可以直接使用的路径
+ */
+export function pathInit({ dbName = "database", path = "", user = true, validator = () => true, defaultValue = "" }) {
+ const uuid = db.get("database.public.uuid").value() ? db.get("database.public.uuid") : "ghost-uuid";
+ const currentPath = `${dbName}.${user ? `user.${uuid}` : "public"}${path ? `.${path}` : ""}`;
+ const value = db.get(currentPath).value();
+ if (!(value !== undefined && validator(value))) {
+ db.set(currentPath, defaultValue).write();
+ }
+ return currentPath;
+}
+
+/**
+ * @description 将数据存储到指定位置 | 路径不存在会自动初始化
+ * @description 效果类似于取值 dbName.path = value
+ * @param {Object} payload dbName {String} 数据库名称
+ * @param {Object} payload path {String} 存储路径
+ * @param {Object} payload value {*} 需要存储的值
+ * @param {Object} payload user {Boolean} 是否区分用户
+ */
+export function dbSet({ dbName = "database", path = "", value = "", user = false }) {
+ db.set(
+ pathInit({
+ dbName,
+ path,
+ user,
+ }),
+ value
+ ).write();
+}
+
+/**
+ * @description 获取数据
+ * @description 效果类似于取值 dbName.path || defaultValue
+ * @param {Object} payload dbName {String} 数据库名称
+ * @param {Object} payload path {String} 存储路径
+ * @param {Object} payload defaultValue {*} 取值失败的默认值
+ * @param {Object} payload user {Boolean} 是否区分用户
+ */
+export function dbGet({ dbName = "database", path = "", defaultValue = "", user = false }) {
+ return cloneDeep(
+ db
+ .get(
+ pathInit({
+ dbName,
+ path,
+ user,
+ defaultValue,
+ })
+ )
+ .value()
+ );
+}
+
+/**
+ * @description 获取存储数据库对象
+ * @param {Object} payload user {Boolean} 是否区分用户
+ */
+export function database({ dbName = "database", path = "", user = false, validator = () => true, defaultValue = "" } = {}) {
+ return db.get(
+ pathInit({
+ dbName,
+ path,
+ user,
+ validator,
+ defaultValue,
+ })
+ );
+}
diff --git a/src/libs/util.filter.js b/src/libs/util.filter.js
new file mode 100644
index 0000000..f256e1e
--- /dev/null
+++ b/src/libs/util.filter.js
@@ -0,0 +1,120 @@
+let dayjs = require("dayjs");
+import { round, split, join, size } from "lodash";
+import tools from "@/libs/util.tool.js";
+
+const vFilter = {
+ /**
+ * @description 没有值返回 -
+ */
+ filterDefaultVal(value) {
+ if (!value && value !== 0) return "-";
+ return value;
+ },
+ /**
+ * @description 判断数字 且增加百分号 没有则返回-
+ */
+ filterPercentage(value) {
+ if (value === "-" || value === 0) return value;
+ return round(value, 0) + "%";
+ },
+ /**
+ * @description 格式化配速 或分秒结构
+ */
+ filterTimeMS(value) {
+ //console.log(value);
+ if (value === "-") return value;
+ if (value == 0) return "0秒";
+ if (!value) return 0;
+ let num = new Number(value);
+ num = num.toFixed(0);
+ let mm = parseInt(num / 60);
+ let ss = num - mm * 60;
+
+ return mm + "分" + ss + "秒";
+ },
+ /**
+ * @description 米=>公里
+ */
+ filterDistanceSum(value) {
+ if (value === "-" || value === 0) return value;
+ if (!value) return "-";
+ let num = new Number(value);
+
+ return num / 1000;
+ },
+ /**
+ * @description 格式化时间
+ * @parmas format => 标准时间格式
+
+ */
+ filterDayFormat4unix(value, format) {
+ if (value === "-" || value === 0) return value;
+ if (!value) return "-";
+ return dayjs(value).format(format);
+ },
+ filterDayFormat(value, format) {
+ if (value === "-" || value === 0) return value;
+ if (!value) return "-";
+ let _val = dayjs(value);
+
+ return dayjs(_val).format(format);
+ },
+ /**
+ * @description 没有值返回 -
+ */
+ filterDayErrorDuration(value) {
+ if (dayjs(value).get("year") > 2010) {
+ return value;
+ } else {
+ return "-";
+ }
+ },
+ /**
+ * @description 格式化
+ */
+ filterSexVal(value) {
+ value = Number(value);
+ switch (value) {
+ case 1:
+ return "男";
+ break;
+ case 0:
+ return "女";
+ break;
+ default:
+ return "-";
+ break;
+ }
+ },
+ /**
+ * @description 生日计算虚岁
+ */
+ filterSexVal(date) {
+ if (date === "-" || date === 0) return date;
+
+ let _dayjs = dayjs(date);
+ return dayjs().year() - _dayjs.year();
+ },
+ /**
+ * @description 计算显示最大字数
+ */
+ filterStrSize(value, lens) {
+ let _split, _res;
+ let _lens = tools.getByteLen(value);
+
+ if (_lens > lens) {
+ let _curlens = tools.getByteCurLen4Size(value, lens);
+ //console.log(_curlens);
+
+ _split = split(value, "", _curlens);
+ _split.push("...");
+ _res = join(_split, "");
+ } else {
+ return value;
+ }
+
+ return _res;
+ },
+};
+
+export default vFilter;
diff --git a/src/libs/util.js b/src/libs/util.js
new file mode 100644
index 0000000..ab2e0f3
--- /dev/null
+++ b/src/libs/util.js
@@ -0,0 +1,11 @@
+import db from "./util.db";
+import token from "./util.token";
+import url from "./util.url";
+
+const util = {
+ db,
+ url,
+ token,
+};
+
+export default util;
diff --git a/src/libs/util.message.js b/src/libs/util.message.js
new file mode 100644
index 0000000..24e32e0
--- /dev/null
+++ b/src/libs/util.message.js
@@ -0,0 +1,32 @@
+import { Toast } from "vant";
+
+const msg = {};
+
+msg.success = function(msg) {
+ Toast.success({
+ message: msg,
+ duration: 2000,
+ showClose: true,
+ });
+};
+
+msg.error = function(msg) {
+ Toast.fail({
+ message: msg,
+ duration: 2000,
+ showClose: true,
+ });
+};
+
+msg.loading = function(msg) {
+ let _toast = Toast.loading({
+ message: msg,
+ duration: 0,
+ showClose: true,
+ // className: "sys-my-toash",
+ forbidClick: true,
+ });
+ return _toast;
+};
+
+export default msg;
diff --git a/src/libs/util.token.js b/src/libs/util.token.js
new file mode 100644
index 0000000..24c841d
--- /dev/null
+++ b/src/libs/util.token.js
@@ -0,0 +1,53 @@
+import { dbSet, dbGet } from "./util.db";
+import api from "@/api";
+import { now } from "lodash";
+
+// 处理用户体系相关判断
+
+const token = {};
+/**
+ * @description 判断本地token是否有效
+ * @return true => 有效
+ */
+export function isActiveToken() {
+ const timeout = dbGet({ path: "token.expired" });
+ const _token = dbGet({ path: "token.value" });
+ let _access = true;
+ if (_token) {
+ // 注意 毫秒时间戳
+ if (timeout < now()) {
+ _access = false;
+ removeToken();
+ }
+ } else {
+ _access = false;
+ }
+ return _access;
+}
+
+// 删除token
+export function removeToken() {
+ dbSet({ path: "token", value: {} });
+}
+
+export function setToken(token, time) {
+ const tokenData = { value: token, expired: now() + time * 1000 };
+ const data = { path: "token", value: tokenData };
+ dbSet(data);
+}
+
+export function getToken() {
+ return dbGet({ path: "token.value" });
+}
+
+export function BSkeySet(SecretKey, time) {
+ const BSkeyData = { value: SecretKey, expired: time };
+ const data = { path: "BSkey", value: BSkeyData };
+ dbSet(data);
+}
+export function BSkeyGet() {
+ // 返回 秘钥以及有效期
+ return dbGet({ path: "BSkey" });
+}
+
+export default token;
diff --git a/src/libs/util.tool.js b/src/libs/util.tool.js
new file mode 100644
index 0000000..d055d7d
--- /dev/null
+++ b/src/libs/util.tool.js
@@ -0,0 +1,35 @@
+const tools = {};
+export default tools;
+
+export function getByteLen(val) {
+ let len = 0;
+ for (let i = 0; i < val.length; i++) {
+ let a = val.charAt(i);
+ if (a.match(/[^\x00-\xff]/gi) != null) {
+ len += 1;
+ } else {
+ len += 0.5;
+ }
+ }
+ return len;
+}
+
+export function getByteCurLen4Size(val, size) {
+ let len = 0;
+ let curlen = 0;
+
+ for (let i = 0; i < val.length; i++) {
+ let a = val.charAt(i);
+ if (a.match(/[^\x00-\xff]/gi) != null) {
+ len += 1;
+ } else {
+ len += 0.5;
+ }
+ curlen += 1;
+
+ if (len >= size) {
+ break;
+ }
+ }
+ return curlen;
+}
diff --git a/src/libs/util.url.js b/src/libs/util.url.js
new file mode 100644
index 0000000..576f218
--- /dev/null
+++ b/src/libs/util.url.js
@@ -0,0 +1,12 @@
+const url = {};
+export default url;
+
+url.getQueryString = (name) => {
+ const locString = window.location.href;
+ let rs = new RegExp("(^|)" + name + "=([^&]*)(&|$)", "gi").exec(locString),
+ tmp;
+ if ((tmp = rs)) {
+ return decodeURI(tmp[2]);
+ }
+ return "";
+};
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..8056d77
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,54 @@
+import Vue from "vue";
+import App from "./App.vue";
+import router from "./router";
+import store from "@/store/index";
+
+// 自适配 rem
+import "amfe-flexible";
+import "amfe-flexible/index.js";
+
+// 框架插件
+import plugin from "@/plugin/index";
+import vueFilter from "@/libs/util.filter.js";
+
+Vue.use(plugin);
+
+// add 全局过滤器
+for (let key in vueFilter) {
+ Vue.filter(key, vueFilter[key]);
+}
+
+import Vant from "vant";
+import "vant/lib/index.css";
+Vue.use(Vant);
+
+import "element-ui/lib/theme-chalk/index.css";
+import ElementUI from "element-ui";
+Vue.use(ElementUI);
+
+import * as echarts from "echarts";
+Vue.prototype.$echarts = echarts;
+import { Toast } from "vant";
+Vue.prototype.$toast = Toast;
+Toast.allowMultiple();
+
+Vue.config.productionTip = false;
+
+// 轻量级 播放器
+import vueMiniPlayer from "vue-mini-player";
+import "vue-mini-player/lib/vue-mini-player.css";
+Vue.use(vueMiniPlayer);
+
+// 导出插件
+import JsonExcel from "vue-json-excel";
+Vue.component("DownloadExcel", JsonExcel);
+
+// import Vconsole from "vconsole";
+// let vConsole = new Vconsole();
+// Vue.use(vConsole);
+
+new Vue({
+ router,
+ store,
+ render: (h) => h(App),
+}).$mount("#app");
diff --git a/src/plugin/index.js b/src/plugin/index.js
new file mode 100644
index 0000000..d85aa1a
--- /dev/null
+++ b/src/plugin/index.js
@@ -0,0 +1,9 @@
+import msg from "@/libs/util.message";
+import api from "@/api";
+
+export default {
+ install(Vue) {
+ Vue.prototype.$msg = msg;
+ Vue.prototype.$api = api;
+ },
+};
diff --git a/src/router/index.js b/src/router/index.js
new file mode 100644
index 0000000..d725f99
--- /dev/null
+++ b/src/router/index.js
@@ -0,0 +1,84 @@
+import Vue from "vue";
+import VueRouter from "vue-router";
+import { includes, concat, get, values } from "lodash";
+
+import { isActiveToken } from "@/libs/util.token";
+import store from "../store";
+
+Vue.use(VueRouter);
+
+import mobile from "./modules/mobile";
+import pc from "./modules/pc";
+import system from "./modules/system";
+
+const routes = concat(system.children, mobile.children, pc.children);
+
+const router = new VueRouter({
+ // mode: "history",
+ base: process.env.VUE_APP_PUBLIC_PATH,
+ routes,
+});
+
+// 路由守卫 进入路由之前
+router.beforeEach(async (to, from, next) => {
+ // 完整cur域名 wxjdk调用
+ let curHref = window.location.href.split("#")[0];
+ store.commit("plugin/wechat/setState", { name: "curHref", value: curHref });
+ store.commit("plugin/wechat/setRedirUrl", { url: to.path });
+ store.commit("plugin/wechat/setState", { name: "type", value: to.meta.type });
+ store.dispatch("plugin/loading/open", "globalLoading");
+
+ let login = get(to.meta, "login", false);
+ if (login) {
+ await store.dispatch("plugin/wechat/userLogin");
+ next();
+ }
+
+ if (to.meta.auth) {
+ let _access = isActiveToken();
+ if (_access) {
+ next();
+ } else {
+ if (to.meta.type === "mobile") {
+ await store.dispatch("plugin/wechat/callbackWechat");
+ } else {
+ store.dispatch("plugin/loading/close", "globalLoading");
+ next({ path: "/pc/login" });
+ }
+ }
+ } else {
+ next();
+ }
+});
+
+router.beforeResolve(async (to, from, next) => {
+ let usrRegister = get(store.getters, "manage/register/userRegister", "");
+
+ if (to.meta.type === "mobile" && to.path !== "/mobile/register" && usrRegister) {
+ let doRegister = get(store.state, "manage.register.doRegister");
+ if (doRegister === false) {
+ next({ path: "/mobile/register" });
+ }
+ }
+
+ let title = get(store.state, "plugin.baseinfo.title");
+ if (title) {
+ document.title = title;
+ } else {
+ document.title = process.env.VUE_APP_TITLE;
+ }
+ // 下拉刷新开关
+ if (to.meta.refresh) {
+ store.dispatch("plugin/page/able", "doRefresh");
+ } else {
+ store.dispatch("plugin/page/disable", "doRefresh");
+ }
+ // 防止屏幕抖动
+ setTimeout(() => {
+ store.dispatch("plugin/loading/close", "globalLoading");
+ }, 500);
+
+ next();
+});
+
+export default router;
diff --git a/src/router/modules/mobile/index.js b/src/router/modules/mobile/index.js
new file mode 100644
index 0000000..2b9f594
--- /dev/null
+++ b/src/router/modules/mobile/index.js
@@ -0,0 +1,38 @@
+let login = true;
+let auth = true;
+let refresh = true;
+
+export default {
+ children: ((pre) => [
+ // {
+ // meta: { auth, type: pre, login, refresh },
+ // path: `/`,
+ // name: `index`,
+ // component: () => import("@views/manage/mobile/index"),
+ // },
+ // {
+ // path: `/${pre}/register`,
+ // name: `${pre}register`,
+ // component: () => import("@views/manage/mobile/register"),
+ // meta: { auth, type: pre },
+ // },
+ // {
+ // path: `/${pre}/question`,
+ // name: `${pre}question`,
+ // component: () => import("@views/manage/mobile/question"),
+ // meta: { auth, type: pre },
+ // },
+ // {
+ // path: `/${pre}/result`,
+ // name: `${pre}result`,
+ // component: () => import("@views/manage/mobile/result"),
+ // meta: { auth, type: pre },
+ // },
+ // {
+ // path: `/${pre}/test`,
+ // name: `${pre}test`,
+ // component: () => import("@views/manage/indextest"),
+ // meta: { auth, type: pre, login },
+ // },
+ ])("mobile"),
+};
diff --git a/src/router/modules/pc/index.js b/src/router/modules/pc/index.js
new file mode 100644
index 0000000..6b800d4
--- /dev/null
+++ b/src/router/modules/pc/index.js
@@ -0,0 +1,12 @@
+let login = true;
+let auth = true;
+
+export default {
+ children: ((pre) => [
+ // {
+ // path: `/${pre}/login`,
+ // name: `${pre}login`,
+ // component: () => import("@views/manage/pc/login"),
+ // },
+ ])("pc"),
+};
diff --git a/src/router/modules/system/index.js b/src/router/modules/system/index.js
new file mode 100644
index 0000000..0a6b437
--- /dev/null
+++ b/src/router/modules/system/index.js
@@ -0,0 +1,17 @@
+const meta = { auth: true };
+
+export default {
+ children: [
+ {
+ // 刷新页面
+ path: "/",
+ component: () => import("@views/index"),
+ },
+ {
+ // 刷新页面
+ path: "/redirect/:path*",
+ name: "redirect",
+ component: () => import("@views/redirect"),
+ },
+ ],
+};
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 0000000..1f226b6
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,29 @@
+import Vue from "vue";
+import Vuex from "vuex";
+import createPersistedState from "vuex-persistedstate";
+
+import plugin from "./modules/plugin";
+import manage from "./modules/manage";
+
+import { set } from "lodash";
+Vue.use(Vuex);
+
+export default new Vuex.Store({
+ modules: {
+ plugin,
+ manage,
+ },
+ plugins: [
+ createPersistedState({
+ key: `${process.env.VUE_APP_LOCAL_CODE}-${process.env.VUE_APP_VERSION}-persisted`,
+ reducer(val) {
+ let _res = {};
+ set(_res, "manage", val.manage);
+ set(_res, "plugin.wechat.appid", val.plugin.wechat.appid);
+ set(_res, "plugin.baseinfo", val.plugin.baseinfo);
+
+ return _res;
+ },
+ }),
+ ],
+});
diff --git a/src/store/modules/manage/index.js b/src/store/modules/manage/index.js
new file mode 100644
index 0000000..9b75abe
--- /dev/null
+++ b/src/store/modules/manage/index.js
@@ -0,0 +1,16 @@
+/**
+ * The file enables `@/store/index.js` to import all vuex modules
+ * in a one-shot manner. There should not be any reason to edit this file.
+ */
+
+const files = require.context("./modules", true, /\.js$/);
+const modules = {};
+
+files.keys().forEach((key) => {
+ modules[key.replace(/(\.\/|\.js)/g, "")] = files(key).default;
+});
+
+export default {
+ namespaced: true,
+ modules,
+};
diff --git a/src/store/modules/manage/modules/question.js b/src/store/modules/manage/modules/question.js
new file mode 100644
index 0000000..ea4ab90
--- /dev/null
+++ b/src/store/modules/manage/modules/question.js
@@ -0,0 +1,170 @@
+import { set, get, map, isArray, isObject, size, isEmpty } from "lodash";
+import apis from "@/api";
+import { now } from "lodash";
+import router from "@/router/index";
+
+export default {
+ namespaced: true,
+ state: {
+ // bind开关
+ nowQs: 1,
+ nowOptions: [],
+ nowQsList: {},
+ nowAsw: "",
+ allQsList: "",
+ historyQsList: [],
+ historyOtList: [],
+ answerQsList: {},
+ start: "",
+ duration: "",
+ submit: false,
+ errorList: [],
+ redpackMsg: "恭喜发财",
+ },
+ getters: {
+ qsSize: (state) => {
+ return size(state.allQsList);
+ },
+ errorSize: (state, getters) => {
+ return size(getters.errorDetailList);
+ },
+ errorDetailList: (state) => {
+ let qsList = state.allQsList;
+ let opList = state.historyOtList;
+ let myasw = state.historyQsList;
+ let curasw = state.errorList;
+ let _res = [];
+
+ for (let index = 0; index < qsList.length; index++) {
+ const item = qsList[index];
+ let _qsID = item.ID;
+ let cur = get(curasw, _qsID, "");
+ let err = get(myasw, index + 1, "");
+
+ // 获取正确答案 没有则回答正确
+ if (cur !== "" && cur !== err) {
+ let content = item.Content;
+ let options = get(opList, index + 1, "");
+ _res.push({ index: index + 1, cur, err, content, options });
+ }
+ }
+ return _res;
+ },
+ },
+ mutations: {
+ setState(state, payload) {
+ set(state, payload.name, payload.value);
+ },
+ clearState(state, payload) {
+ let _val = get(state, payload.name);
+ if (isArray(_val)) {
+ set(state, payload.name, []);
+ } else if (isObject(_val)) {
+ set(state, payload.name, {});
+ } else {
+ set(state, payload.name, "");
+ }
+ },
+ next(state, payload) {
+ if (payload.qsSize === state.nowQs) return;
+ set(state, "nowQs", state.nowQs + 1);
+ },
+ last(state) {
+ if (state.nowQs === 1) return;
+ let lastQs = state.nowQs - 1;
+ set(state, "nowQs", lastQs);
+ },
+ },
+ actions: {
+ /**
+ * @description 保存当前题目答案
+ */
+ save({ state, commit }, payload) {
+ let qs = state.nowQs;
+ commit("setState", { name: ["historyQsList", qs], value: state.nowAsw });
+ commit("setState", { name: ["answerQsList", state.nowQsList.ID], value: state.nowAsw });
+
+ commit("next", payload);
+ },
+
+ /**
+ * @description 下载新题目
+ */
+ async loadQuestion({ commit }, payload) {
+ const _this = this;
+ commit("clearState", { name: "allQsList" });
+
+ let res = await apis.loadQuestionList();
+ if (res === false) return;
+ commit("setState", { name: "allQsList", value: res });
+ },
+ /**
+ * @description 根据nowQs 下载选项
+ */
+ async loadQuestionItem({ state, commit }, payload) {
+ const _this = this;
+ commit("clearState", { name: "nowOptions" });
+ let id = state.nowQsList.ID;
+ let data = { id };
+ let res = await apis.loadQuestionItem(data);
+ if (res === false) return;
+ commit("setState", { name: "nowOptions", value: res });
+ commit("setState", { name: ["historyOtList", state.nowQs], value: res });
+ },
+ /**
+ * @description 切换题目
+ */
+ async switchQs({ state, commit, dispatch }, payload) {
+ let nowQsObj = get(state.allQsList, state.nowQs - 1);
+ commit("clearState", { name: "nowAsw" });
+ commit("setState", { name: "nowQsList", value: nowQsObj });
+
+ // 判断是否上一题
+ let nextQsAsw = get(state.historyQsList, state.nowQs, "");
+ if (nextQsAsw !== "") {
+ commit("setState", { name: "nowAsw", value: nextQsAsw });
+ commit("setState", { name: "nowOptions", value: get(state.historyOtList, state.nowQs, "") });
+ } else {
+ await dispatch("loadQuestionItem");
+ }
+ },
+ /**
+ * @description 提交题目
+ */
+ async questionSubmit({ state, commit, dispatch, rootState }, payload) {
+ const _this = this;
+ let id = state.nowQsList.ID;
+
+ let duration = parseInt((now() - state.start) / 1000);
+ let location = rootState.plugin.wechat.location;
+ let answer = state.answerQsList;
+ let inarea = rootState.plugin.wechat.inArea === true ? "是" : "否";
+ // console.log(location, inarea);
+
+ let res = await apis.questionSubmit({ duration, location, answer, inarea });
+
+ if (res === false) return false;
+ commit("setState", { name: "errorList", value: res.Reply });
+ commit("setState", { name: "duration", value: duration });
+ commit("setState", { name: "redpackMsg", value: res.Message });
+
+ // commit("setState", { name: "submit", value: true });
+ },
+ /**
+ * @description 首次进入
+ */
+ async firstQs({ state, commit, dispatch }, payload) {
+ commit("setState", { name: "nowQs", value: 1 });
+ commit("setState", { name: "submit", value: false });
+ commit("setState", { name: "start", value: now() });
+ },
+ /**
+ * @description 首次进入清空保存项
+ */
+ async clearQuestion({ commit }, payload) {
+ commit("clearState", { name: "historyQsList" });
+ commit("clearState", { name: "historyOtList" });
+ commit("clearState", { name: "answerQsList" });
+ },
+ },
+};
diff --git a/src/store/modules/manage/modules/register.js b/src/store/modules/manage/modules/register.js
new file mode 100644
index 0000000..1f755b6
--- /dev/null
+++ b/src/store/modules/manage/modules/register.js
@@ -0,0 +1,78 @@
+import { set, get, map, isArray, isObject, size, isEmpty } from "lodash";
+import apis from "@/api";
+import router from "@/router/index";
+import { Toast } from "vant";
+import msg from "@/libs/util.message";
+
+export default {
+ namespaced: true,
+ state: {
+ user: {},
+ doRegister: false,
+ adminAreaList: "",
+ adminList: "",
+ },
+ getters: {
+ userRegister: (state) => {
+ let Mobile = get(state.user, "Mobile", "");
+ let IDCard = get(state.user, "IDCard", "");
+ let AdminID = get(state.user, "AdminID", "");
+ if (isEmpty(Mobile) || isEmpty(IDCard) || isEmpty(AdminID)) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ },
+ mutations: {
+ setState(state, payload) {
+ set(state, payload.name, payload.value);
+ },
+ clearState(state, payload) {
+ let _val = get(state, payload.name);
+ if (isArray(_val)) {
+ set(state, payload.name, []);
+ } else if (isObject(_val)) {
+ set(state, payload.name, {});
+ } else {
+ set(state, payload.name, "");
+ }
+ },
+ },
+ actions: {
+ /**
+ * 获取网格长数据
+ */
+ async loadAdminPerson({ commit }, data) {
+ commit("clearState", { name: "adminList" });
+ if (isEmpty(data)) {
+ return;
+ }
+
+ let res = await apis.loadAdminPerson(data);
+ if (res === false) return;
+ commit("setState", { name: "adminList", value: res });
+ },
+ /**
+ * 获取辖区数据
+ */
+ async loadAdminArea({ commit, state }) {
+ commit("clearState", { name: "adminAreaList" });
+ let res = await apis.loadAdminArea();
+
+ if (res === false) return;
+ commit("setState", { name: "adminAreaList", value: res });
+ },
+ /**
+ * 提交注册
+ */
+ async answererRegister({ commit, state }, data) {
+ let res = await apis.answererRegister(data);
+
+ if (res === false) return;
+ commit("plugin/tools/setState", { name: "searchList", value: res }, { root: true });
+ commit("setState", { name: "doRegister", value: true });
+ return true;
+ },
+ },
+};
diff --git a/src/store/modules/manage/modules/statistics.js b/src/store/modules/manage/modules/statistics.js
new file mode 100644
index 0000000..f502be7
--- /dev/null
+++ b/src/store/modules/manage/modules/statistics.js
@@ -0,0 +1,107 @@
+import { set, get, map, isArray, isObject, size, cloneDeep } from "lodash";
+import apis from "@/api";
+import router from "@/router/index";
+import { Toast } from "vant";
+import msg from "@/libs/util.message";
+let dayjs = require("dayjs");
+
+export default {
+ namespaced: true,
+ state: {
+ baseinfo: [],
+ adminInfo: [],
+ answerInfo: [],
+ feeInfo: [],
+ start: "",
+ end: "",
+ id: 0,
+ answerSearchNumber: "",
+ },
+ getters: {
+ adminInfo: (state) => {
+ let adminInfo = cloneDeep(state.adminInfo);
+ return map(adminInfo, (item) => {
+ item.rate = ((item.ParticipateCount / item.PeopleCount) * 100).toFixed(1) + "%";
+ item.curRate = ((item.ParticipateCount / item.PeopleCount) * 100).toFixed(1);
+ return item;
+ });
+ },
+ },
+ mutations: {
+ setState(state, payload) {
+ let name = payload.name;
+ let value = payload.value;
+
+ if (!isArray(name)) {
+ set(state, name, value);
+ } else {
+ if (size(name) === size(value) && isArray(value)) {
+ map(name, (item, index) => set(state, item, get(value, index)));
+ } else {
+ map(name, (item) => set(state, item, value));
+ }
+ }
+ },
+ clearState(state, payload) {
+ let _val = get(state, payload.name);
+ if (isArray(_val)) {
+ set(state, payload.name, []);
+ } else if (isObject(_val)) {
+ set(state, payload.name, {});
+ } else {
+ set(state, payload.name, "");
+ }
+ },
+ },
+ actions: {
+ /**
+ * 获取 基础信息
+ */
+ async loadSummary({ commit, state }) {
+ const _this = this;
+ commit("clearState", { name: "baseinfo" });
+ let res = await apis.loadSummary();
+
+ if (res === false) return;
+ commit("setState", { name: "baseinfo", value: res });
+ },
+ /**
+ * 获取 考核信息
+ */
+ async loadAssessment({ commit, state }) {
+ const _this = this;
+ commit("clearState", { name: "adminInfo" });
+ let res = await apis.loadAssessment();
+
+ if (res === false) return;
+ commit("setState", { name: "adminInfo", value: res });
+ },
+ /**
+ * 获取 用户信息
+ */
+ async loadAnalysis({ commit, state }) {
+ const _this = this;
+ commit("clearState", { name: "answerInfo" });
+ let id = state.id;
+ if (id === 0) id = "";
+
+ let data = { id, start: state.start, end: state.end };
+ let res = await apis.loadAnalysis(data);
+
+ if (res === false) return;
+ //console.log(res);
+ commit("setState", { name: "answerInfo", value: res });
+ },
+ /**
+ * 获取 奖励发放时间
+ */
+ async loadFee({ commit, state }) {
+ commit("clearState", { name: "feeInfo" });
+ let res = await apis.loadFee();
+
+ if (res === false) return;
+ //console.log(res);
+ commit("setState", { name: "feeInfo", value: res });
+ },
+ },
+};
diff --git a/src/store/modules/plugin/index.js b/src/store/modules/plugin/index.js
new file mode 100644
index 0000000..9b75abe
--- /dev/null
+++ b/src/store/modules/plugin/index.js
@@ -0,0 +1,16 @@
+/**
+ * The file enables `@/store/index.js` to import all vuex modules
+ * in a one-shot manner. There should not be any reason to edit this file.
+ */
+
+const files = require.context("./modules", true, /\.js$/);
+const modules = {};
+
+files.keys().forEach((key) => {
+ modules[key.replace(/(\.\/|\.js)/g, "")] = files(key).default;
+});
+
+export default {
+ namespaced: true,
+ modules,
+};
diff --git a/src/store/modules/plugin/modules/baseinfo.js b/src/store/modules/plugin/modules/baseinfo.js
new file mode 100644
index 0000000..a27a69a
--- /dev/null
+++ b/src/store/modules/plugin/modules/baseinfo.js
@@ -0,0 +1,59 @@
+import { set, get, map, isArray, isObject, size, isEmpty } from "lodash";
+import apis from "@/api";
+import router from "@/router/index";
+import { Toast } from "vant";
+import msg from "@/libs/util.message";
+
+export default {
+ namespaced: true,
+ state: {
+ title: "",
+ orgName: "",
+ },
+ getters: {},
+ mutations: {
+ setState(state, payload) {
+ let name = payload.name;
+ let value = payload.value;
+
+ if (!isArray(name)) {
+ set(state, name, value);
+ } else {
+ if (size(name) === size(value) && isArray(value)) {
+ map(name, (item, index) => set(state, item, get(value, index)));
+ } else {
+ map(name, (item) => set(state, item, value));
+ }
+ }
+ },
+ clearState(state, payload) {
+ let _val = get(state, payload.name);
+ if (isArray(_val)) {
+ set(state, payload.name, []);
+ } else if (isObject(_val)) {
+ set(state, payload.name, {});
+ } else {
+ set(state, payload.name, "");
+ }
+ },
+ },
+ actions: {
+ /**
+ * 设置页面title
+ */
+ setWebBaseInfo({ state, commit, rootState }) {
+ let user = rootState.manage.register.user;
+ let orgName = user.OrgName;
+ let ProJName = user.ProjectName;
+ commit("setState", { name: ["orgName", "title"], value: [orgName, ProJName] });
+ },
+
+ /**
+ * 是否首页
+ */
+ async getTitleSet({ state, commit, rootState }) {
+ let title = state.title;
+ //console.log(title);
+ },
+ },
+};
diff --git a/src/store/modules/plugin/modules/dialog.js b/src/store/modules/plugin/modules/dialog.js
new file mode 100644
index 0000000..269b01f
--- /dev/null
+++ b/src/store/modules/plugin/modules/dialog.js
@@ -0,0 +1,27 @@
+import { set } from "lodash";
+export default {
+ namespaced: true,
+ state: {
+ // bind开关
+ addDeviceId: false,
+ },
+ mutations: {
+ setVisible(state, payload) {
+ set(state, payload.dialogName, payload.dialogVisible);
+ },
+ },
+ actions: {
+ /**
+ * @description 开启弹窗
+ */
+ open({ commit }, name) {
+ commit("setVisible", { dialogName: name, dialogVisible: true });
+ },
+ /**
+ * @description 关闭弹窗
+ */
+ close({ commit }, name) {
+ commit("setVisible", { dialogName: name, dialogVisible: false });
+ },
+ },
+};
diff --git a/src/store/modules/plugin/modules/loading.js b/src/store/modules/plugin/modules/loading.js
new file mode 100644
index 0000000..16ae407
--- /dev/null
+++ b/src/store/modules/plugin/modules/loading.js
@@ -0,0 +1,39 @@
+import { set } from "lodash";
+
+export default {
+ namespaced: true,
+ state: {
+ // 全局开关
+ globalLoading: true,
+ refreshLoading: false,
+ },
+ mutations: {
+ setVisible(state, payload) {
+ set(state, payload.name, payload.visible);
+ },
+ },
+ actions: {
+ /**
+ * @description 开启对应加载条
+ */
+ open({ commit }, name) {
+ commit("setVisible", { name: name, visible: true });
+ },
+ /**
+ * @description 关闭对应加载条
+ */
+ close({ commit }, name) {
+ commit("setVisible", { name: name, visible: false });
+ },
+ /**
+ * @description 页面刷新
+ */
+ refresh({ commit, dispatch }) {
+ // commit("setVisible", { name: "refreshLoading", visible: false });
+
+ setTimeout(() => {
+ dispatch("close", "refreshLoading");
+ }, 1000);
+ },
+ },
+};
diff --git a/src/store/modules/plugin/modules/page.js b/src/store/modules/plugin/modules/page.js
new file mode 100644
index 0000000..15f417f
--- /dev/null
+++ b/src/store/modules/plugin/modules/page.js
@@ -0,0 +1,28 @@
+import { set } from "lodash";
+
+export default {
+ namespaced: true,
+ state: {
+ doRefresh: true,
+ },
+
+ mutations: {
+ setVisible(state, payload) {
+ set(state, payload.name, payload.visible);
+ },
+ },
+ actions: {
+ /**
+ * @description 展示
+ */
+ able({ commit }, name) {
+ commit("setVisible", { name: name, visible: true });
+ },
+ /**
+ * @description 隐藏
+ */
+ disable({ commit }, name) {
+ commit("setVisible", { name: name, visible: false });
+ },
+ },
+};
diff --git a/src/store/modules/plugin/modules/show.js b/src/store/modules/plugin/modules/show.js
new file mode 100644
index 0000000..a59c31e
--- /dev/null
+++ b/src/store/modules/plugin/modules/show.js
@@ -0,0 +1,29 @@
+import { set } from "lodash";
+
+export default {
+ namespaced: true,
+ state: {
+ showPos: false,
+ showHls: false,
+ },
+
+ mutations: {
+ setVisible(state, payload) {
+ set(state, payload.comName, payload.visible);
+ },
+ },
+ actions: {
+ /**
+ * @description 展示
+ */
+ display({ commit }, name) {
+ commit("setVisible", { comName: name, visible: true });
+ },
+ /**
+ * @description 隐藏
+ */
+ hide({ commit }, name) {
+ commit("setVisible", { comName: name, visible: false });
+ },
+ },
+};
diff --git a/src/store/modules/plugin/modules/switch.js b/src/store/modules/plugin/modules/switch.js
new file mode 100644
index 0000000..1f62130
--- /dev/null
+++ b/src/store/modules/plugin/modules/switch.js
@@ -0,0 +1,14 @@
+import { set } from "lodash";
+
+export default {
+ namespaced: true,
+ state: {
+ duration: "", // 日,周,月,年的英文 与dayjs (add, subtract)方法强关联 如果参数值变更 请修改相关方法
+ },
+ mutations: {
+ setState(state, payload) {
+ set(state, payload.name, payload.value);
+ },
+ },
+ actions: {},
+};
diff --git a/src/store/modules/plugin/modules/tools.js b/src/store/modules/plugin/modules/tools.js
new file mode 100644
index 0000000..64b1b4f
--- /dev/null
+++ b/src/store/modules/plugin/modules/tools.js
@@ -0,0 +1,58 @@
+import { set, get, map, isArray, isObject, size, isEmpty } from "lodash";
+
+import apis from "@/api";
+
+export default {
+ namespaced: true,
+ state: {
+ searchList: [],
+ checkVal: "",
+ videoUrl: "",
+ noticeList: [],
+ },
+ mutations: {
+ setState(state, payload) {
+ set(state, payload.name, payload.value);
+ },
+ clearState(state, payload) {
+ let _val = get(state, payload.name);
+ if (isArray(_val)) {
+ set(state, payload.name, []);
+ } else if (isObject(_val)) {
+ set(state, payload.name, {});
+ } else {
+ set(state, payload.name, "");
+ }
+ },
+ },
+ actions: {
+ /**
+ * 随机获取一个视频地址
+ */
+ async loadVideoUrl({ commit, state, dispatch }) {
+ const _this = this;
+ let res = await apis.loadVideoUrl();
+
+ if (res === false) return;
+ commit("setState", { name: "videoUrl", value: res });
+ },
+ /**
+ * 视频播放计数
+ */
+ async videoPlayCount() {
+ let res = await apis.videoPlayCount();
+ if (res === false) return;
+ },
+ /**
+ * 头部滚动条 数据
+ */
+ async loadNoticePrice({ commit, state }) {
+ const _this = this;
+ let res = await apis.loadNoticePrice();
+ commit("clearState", { name: "noticeList" });
+
+ if (res === false) return;
+ commit("setState", { name: "noticeList", value: res });
+ },
+ },
+};
diff --git a/src/store/modules/plugin/modules/wechat.js b/src/store/modules/plugin/modules/wechat.js
new file mode 100644
index 0000000..7962e57
--- /dev/null
+++ b/src/store/modules/plugin/modules/wechat.js
@@ -0,0 +1,313 @@
+import util from "@/libs/util";
+import { isActiveToken, setToken, removeToken } from "@/libs/util.token";
+import { set, includes, isEmpty, split } from "lodash";
+import apis from "@/api";
+import router from "@/router/index";
+import { Toast } from "vant";
+import wx from "weixin-js-sdk";
+
+export default {
+ namespaced: true,
+ state: {
+ code: "",
+ appid: "",
+ token: "",
+ loginCount: 0,
+ wx: "",
+ // firstIn: true,
+ curHref: "",
+ redirect_uri: "",
+ orgin: "https://www.yyjishu.com/antifraud/#",
+ location: "",
+ inArea: false,
+ proj: "",
+ isPcLoginSuccess: false,
+ type: "",
+ },
+ getters: {
+ isSuperAdmin: (state, getters, rootState) => {
+ let user = rootState.manage.register.user;
+ if (!user) return false;
+
+ if (user.Role === "街道办") {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ },
+ mutations: {
+ setState(state, payload) {
+ set(state, payload.name, payload.value);
+ },
+ countLogin(state) {
+ set(state, "loginCount", state.loginCount + 1);
+ },
+ setRedirUrl(state, payload) {
+ let host = location.origin + process.env.VUE_APP_PUBLIC_PATH + "#";
+ set(state, "redirect_uri", host + payload.url);
+ },
+ },
+ actions: {
+ /**
+ * @description 无token登录流程
+ */
+
+ async userLogin({ state, commit, dispatch }) {
+ let _doAuth = await dispatch("getUrlCode");
+ if (_doAuth) {
+ let _authSuccess = await dispatch("authUser");
+ if (!_authSuccess) {
+ Toast("用户鉴权失败,建议重新打开页面!");
+ }
+ await dispatch("replaceUrl");
+ }
+ },
+ /**
+ * @description 替换当前页面
+ */
+ async replaceUrl({ state, commit, dispatch }) {
+ let redirUrl = state.redirect_uri;
+ window.location.href = redirUrl;
+ },
+ /**
+ * @description 回调无感登录
+ */
+ async callbackWechat({ commit, dispatch }) {
+ let url = "https://open.weixin.qq.com/connect/oauth2/authorize";
+ let appid = "wxd69449ebd878fa6d";
+ let redirect_uri = "https%3A%2F%2Fwww.yyjishu.com%2Fantifraud%2F%23%2F%3Fproj%3D1%26appid%3Dwxd69449ebd878fa6d";
+ let response_type = "code";
+ let scope = "snsapi_userinfo#wechat_redirect";
+ location.href = `${url}?appid=${appid}&redirect_uri=${redirect_uri}&response_type=${response_type}&scope=${scope}`;
+ },
+ /**
+ * @description 获取url里 code appid proj值 并储存
+ */
+ async getUrlCode({ commit, dispatch }) {
+ let code = util.url.getQueryString("code");
+ let appid = util.url.getQueryString("appid");
+ let proj = util.url.getQueryString("proj");
+
+ if (isEmpty(code) || isEmpty(appid) || isEmpty(proj)) {
+ return false;
+ }
+ commit("setState", { name: "code", value: code });
+ commit("setState", { name: "appid", value: appid });
+ commit("setState", { name: "proj", value: proj });
+ return true;
+ // await dispatch("userLogin");
+ },
+ /**
+ * @description 用户鉴权
+ */
+ async authUser({ state, commit, dispatch }) {
+ let res = await apis.authWx({ code: state.code, appid: state.appid, proj: state.proj });
+ if (res === false) {
+ return false;
+ }
+ let { token, expirein, user } = res;
+ commit("setState", { name: "token", value: token });
+ commit("manage/register/setState", { name: "user", value: user }, { root: true });
+ setToken(token, expirein);
+ // 设置页面基础信息
+ await dispatch("plugin/baseinfo/setWebBaseInfo", {}, { root: true });
+ return true;
+ },
+ /**
+ * @description 用户token失效 提示信息
+ */
+ userInfoFailMsg() {
+ Toast.fail({
+ message: "用户登录失败\n请关闭后重试",
+ overlay: true,
+ duration: 0,
+ });
+ },
+ layout({ commit }) {
+ removeToken();
+ // commit("setState", { name: "firstIn", value: true });
+ commit("setState", "token");
+ },
+ /**
+ * @description 微信jdk 鉴权
+ */
+ async wxConfig({ state, commit, dispatch }) {
+ //通过config接口注入权限验证配置 只要调后端接口就可以了。后端会把那些信息处理好,然后通过一个接口返给你这些参数
+ let appId = state.appid;
+ let uri = state.curHref;
+ //console.log(appId, uri);
+ let res = await apis.loadConfigInfo({ appid: appId, uri });
+ if (res === false) {
+ //console.log("wxconfig 注入失败");
+ return;
+ }
+ let timestamp = res.Timestamp;
+ let signature = res.Signature;
+ let nonceStr = res.NonceStr;
+
+ wx.config({
+ debug: false,
+ appId,
+ timestamp,
+ signature,
+ nonceStr,
+ jsApiList: [
+ "checkJsApi",
+ "onMenuShareTimeline",
+ "onMenuShareAppMessage",
+ "onMenuShareQQ",
+ "onMenuShareWeibo",
+ "onMenuShareQZone",
+ "hideMenuItems",
+ "showMenuItems",
+ "hideAllNonBaseMenuItem",
+ "showAllNonBaseMenuItem",
+ "translateVoice",
+ "startRecord",
+ "stopRecord",
+ "onVoiceRecordEnd",
+ "playVoice",
+ "onVoicePlayEnd",
+ "pauseVoice",
+ "stopVoice",
+ "uploadVoice",
+ "downloadVoice",
+ "chooseImage",
+ "previewImage",
+ "uploadImage",
+ "downloadImage",
+ "getNetworkType",
+ "openLocation",
+ "getLocation",
+ "hideOptionMenu",
+ "showOptionMenu",
+ "closeWindow",
+ "scanQRCode",
+ "chooseWXPay",
+ "openProductSpecificView",
+ "addCard",
+ "chooseCard",
+ "openCard",
+ ],
+ });
+ wx.error(function(res) {
+ Toast(res);
+ });
+
+ commit("setState", { name: "wx", value: wx });
+ },
+
+ /**
+ * 获取地理位置
+ */
+ getLocation({ commit, state, dispatch }) {
+ return new Promise((resolve) => {
+ state.wx.ready(function() {
+ // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
+ state.wx.getLocation({
+ type: "gcj02",
+ success: function(res) {
+ resolve(res);
+ },
+ fail: function(res) {
+ Toast(res);
+ resolve(res);
+ },
+ });
+ });
+ });
+ },
+ async isInArea({ commit, state, dispatch }) {
+ await dispatch("wxConfig");
+ let _getSuceess = dispatch("getLocation");
+ _getSuceess.then((res) => {
+ let { latitude, longitude } = res;
+ console.log(latitude, longitude);
+
+ if (!latitude || !longitude) return;
+ commit("setState", { name: "location", value: latitude + "," + longitude });
+ dispatch("isPointInPolygon");
+ });
+ },
+ isPointInPolygon({ state, commit }) {
+ let path = [
+ new TMap.LatLng(29.943883, 121.602682),
+ new TMap.LatLng(29.955313, 121.602796),
+ new TMap.LatLng(29.957481, 121.606207),
+ new TMap.LatLng(29.960929, 121.605297),
+ new TMap.LatLng(29.961914, 121.602568),
+ new TMap.LatLng(29.97876, 121.603023),
+ new TMap.LatLng(29.978681, 121.6091),
+ new TMap.LatLng(29.980653, 121.609911),
+ new TMap.LatLng(29.980753, 121.60585),
+ new TMap.LatLng(29.988618, 121.60577),
+ new TMap.LatLng(29.988871, 121.606063),
+ new TMap.LatLng(29.994632, 121.605825),
+ new TMap.LatLng(29.994702, 121.606464),
+ new TMap.LatLng(29.996293, 121.606357),
+ new TMap.LatLng(29.996546, 121.607156),
+ new TMap.LatLng(29.998391, 121.606758),
+ new TMap.LatLng(29.998908, 121.605797),
+ new TMap.LatLng(29.999143, 121.605863),
+ new TMap.LatLng(30.001682, 121.608335),
+ new TMap.LatLng(30.001682, 121.608335),
+ new TMap.LatLng(30.008685, 121.615431),
+ new TMap.LatLng(30.009024, 121.618805),
+ new TMap.LatLng(30.003759, 121.620452),
+ new TMap.LatLng(30.002604, 121.617118),
+ new TMap.LatLng(29.993428, 121.620547),
+ new TMap.LatLng(29.993025, 121.619473),
+ new TMap.LatLng(29.992184, 121.619874),
+ new TMap.LatLng(29.991971, 121.620004),
+ new TMap.LatLng(29.992139, 121.620845),
+ new TMap.LatLng(29.987921, 121.623377),
+ new TMap.LatLng(29.989076, 121.625925),
+ new TMap.LatLng(29.984816, 121.628779),
+ new TMap.LatLng(29.984911, 121.632577),
+ new TMap.LatLng(29.979536, 121.635368),
+ new TMap.LatLng(29.980577, 121.637394),
+ new TMap.LatLng(29.975834, 121.643542),
+ new TMap.LatLng(29.97771, 121.641016),
+ new TMap.LatLng(29.979254, 121.643073),
+ new TMap.LatLng(29.97518, 121.647262),
+ new TMap.LatLng(29.9688, 121.636516),
+ new TMap.LatLng(29.965233, 121.642626),
+ new TMap.LatLng(29.964734, 121.637667),
+ new TMap.LatLng(29.961819, 121.640147),
+ new TMap.LatLng(29.960027, 121.636711),
+ new TMap.LatLng(29.963852, 121.632747),
+ new TMap.LatLng(29.960842, 121.630316),
+ new TMap.LatLng(29.958927, 121.631453),
+ new TMap.LatLng(29.956739, 121.626875),
+ new TMap.LatLng(29.956126, 121.627974),
+ new TMap.LatLng(29.953059, 121.626664),
+ new TMap.LatLng(29.950817, 121.624055),
+ new TMap.LatLng(29.951889, 121.622536),
+ new TMap.LatLng(29.951689, 121.614817),
+ new TMap.LatLng(29.949841, 121.608112),
+ new TMap.LatLng(29.948257, 121.605613),
+ new TMap.LatLng(29.943133, 121.603358),
+ ];
+
+ let _resLos = split(state.location, ",");
+ let [lat, lng] = _resLos;
+ // console.log(lat, lng);
+ let userPot = new TMap.LatLng(lat, lng);
+ let res = TMap.geometry.isPointInPolygon(userPot, path);
+ // console.log(res);
+
+ // if (res === false) {
+ // let test = [
+ // new TMap.LatLng(29.816871, 121.486682),
+ // new TMap.LatLng(29.818024, 121.48849),
+ // new TMap.LatLng(29.816262, 121.490207),
+ // new TMap.LatLng(29.814805, 121.488564),
+ // ];
+ // res = TMap.geometry.isPointInPolygon(userPot, test);
+ // }
+
+ commit("setState", { name: "inArea", value: res });
+ },
+ },
+};
diff --git a/src/styles/_var.scss b/src/styles/_var.scss
new file mode 100644
index 0000000..6c762a8
--- /dev/null
+++ b/src/styles/_var.scss
@@ -0,0 +1,43 @@
+/**
+ * 全局变量
+ * 命名规范 —— 遵守语义化命名:lg-大号、md-中号、base-基本号、sm-小号、mini-超小号
+ */
+
+$font-weight-base: bold;
+$font-weight-none: 200px;
+
+$border-color-dark: #e6e6e6;
+$border-color-base: #dcdfe6;
+$border-color-light: #e4e7ed;
+$border-color-lighter: #ebeef5;
+$border-color-xlight: #f2f6fc;
+
+$font-color-primary: #303133;
+$font-color-regular: #606266;
+$font-color-secondary: #909399;
+
+$font-size-lg: xx-large;
+$font-size-md: large;
+$font-size-base: middle;
+$font-size-sm: small;
+$font-size-mini: x-small;
+
+$color-backgroud-primay: white;
+
+$color-primary: #409eff;
+$color-important: #222222;
+$color-common: #606060;
+$color-desc: #909090;
+$color-disabled: #bfbfbf;
+$color-success: #67c23a;
+$color-error: #f56c6c;
+$color-warn: #e6a23c;
+$color-info: #909399;
+$color-lighting: #9013fe;
+
+$line-height-none: 1;
+$line-height-compact: 1.3;
+$line-height-base: 1.5;
+$line-height-loose: 1.7;
+
+$line-pc-margin: 20px;
diff --git a/src/styles/all.scss b/src/styles/all.scss
new file mode 100644
index 0000000..41e7d3a
--- /dev/null
+++ b/src/styles/all.scss
@@ -0,0 +1,490 @@
+
+@import './settings.scss';
+
+$mobile-color-main: #ee6a59;
+$mobile-color-font: #3e3c36;
+$mobile-color-font-secend: #878787;
+$mobile-color-font-contrast: white;
+
+$mobile-color-title: grey;
+
+$mobile-font-thin: 300px;
+$mobile-font-bold: bold;
+$mobile-font-bolder: bolder;
+
+$mobile-padding-left: 1rem;
+.icon-large {
+ width: 8rem;
+ height: 8rem;
+ fill: currentColor;
+ overflow: hidden;
+}
+.icon-big {
+ width: 5rem;
+ height: 5rem;
+ fill: currentColor;
+ overflow: hidden;
+}
+.icon-small {
+ width: 1.2rem;
+ height: 1.2rem;
+ fill: currentColor;
+ overflow: hidden;
+}
+
+.icon-button {
+ width: 3rem;
+ height: 2rem;
+ fill: currentColor;
+ overflow: hidden;
+}
+.icon-button-middle {
+ width: 4rem;
+ height: 3rem;
+ fill: currentColor;
+ overflow: hidden;
+}
+.icon-button-big {
+ width: 5rem;
+ height: 2rem;
+ fill: currentColor;
+ overflow: hidden;
+}
+
+.mobile-box-index {
+ @include wh(100%, auto);
+ padding: 0.7rem $mobile-padding-left;
+ background-color: white;
+
+ .box-title {
+ @include sc($mobile-font-base, $mobile-color-font);
+ text-align: start;
+ line-height: 1.2rem;
+ padding-bottom: 0.5rem;
+ }
+ .box-secend-title {
+ @include sc($mobile-font-sm, $mobile-color-font-secend);
+ text-align: end;
+ line-height: 1.2rem;
+ }
+ .box-map {
+ @include border-radius;
+ }
+
+ .content {
+ @include sc($mobile-font-base, $mobile-color-font);
+ }
+ .content-sm {
+ @include sc($mobile-font-sm, $mobile-color-font);
+ }
+ .grey-backgd {
+ background-color: #f7f8f9;
+ }
+ .icon {
+ width: $mobile-font-base;
+ height: $mobile-font-base;
+ }
+}
+
+.health-box-index {
+ @include border-radius;
+ @include wh(100%, auto);
+
+ background-color: rgb(250, 130, 225, 0.15);
+ margin-bottom: 1rem;
+ padding: 0.5rem 0.2rem;
+ .col-name {
+ @include sc($mobile-font-base, #3e3c36);
+ font-weight: bold;
+ }
+ .col-unit {
+ @include sc($mobile-font-sm, #3e3c36);
+ }
+ .col-content {
+ @include sc($mobile-font-bg, #3e3c36);
+ font-weight: bold;
+ line-height: 3.5rem;
+ text-align: start;
+ padding-left: 1rem;
+ }
+ .col-icon {
+ width: $mobile-font-bg;
+ height: $mobile-font-bg;
+ }
+}
+
+.mobile-box-user {
+ padding-top: 0.5rem;
+
+ .user-name {
+ @include sc($mobile-font-md, $mobile-color-font);
+ font-weight: normal;
+ line-height: 2.5rem;
+ text-align: start;
+ }
+ .org-name {
+ @include sc($mobile-font-xsm, $mobile-color-font);
+ font-weight: bold;
+ line-height: 2.5rem;
+ margin-left: 0.1rem;
+ }
+ .user-avatar {
+ @extend .icon-big;
+ vertical-align: -0.15rem;
+ }
+
+ .user-avatar-switch {
+ width: 2rem;
+ height: 2.8rem;
+ fill: currentColor;
+ overflow: hidden;
+ position: absolute;
+ top: 4.4rem;
+ left: 4rem;
+ }
+ .user-small {
+ @extend .icon-small;
+ vertical-align: -0.24rem;
+ }
+}
+
+.mobile-device-button {
+ background-color: rgb(55, 115, 180, 0.15);
+ border-radius: 1.5rem;
+ padding: 0.1rem 0.5rem;
+ .col-content {
+ @include sc($mobile-font-sm, #5d9eff);
+ }
+ .col-icon {
+ @extend .icon-small;
+ vertical-align: -0.3rem;
+ }
+}
+
+.mobile-postion-box {
+ padding: 0.5rem 0.2rem;
+ background-color: rgb(0, 0, 0, 0);
+
+ .icon {
+ @extend .icon-small;
+ vertical-align: -0.2rem;
+ }
+ .position {
+ @include sc($mobile-font-base, #5d9eff);
+ }
+ .time {
+ @include sc($mobile-font-sm, #878787);
+ }
+}
+
+.mobile-rank-box {
+ padding: 1.2rem 1rem;
+ @include sc($mobile-font-base, #3e3c36);
+ .col-left {
+ text-align: start;
+ }
+ .col-right {
+ text-align: end;
+ }
+}
+
+.mobile-share-index {
+ @include wh(auto, auto);
+ min-height: 100vh;
+ max-width: 100vw;
+ background-color: #f6f7f8;
+ padding: 3.5rem 1rem 2rem 1rem;
+
+ .mobile-share-box {
+ @include border-radius;
+ background-color: #ffffff;
+ padding: 1.2rem 1.2rem 1.2rem 1.2rem;
+ margin-bottom: 1rem;
+ .code-msg {
+ @include sc($mobile-font-sm, #303030);
+ }
+ .main-msg {
+ @include sc($mobile-font-base, #303030);
+ font-weight: bold;
+ }
+ }
+}
+
+.mobile-device-box {
+ @include wh(auto, auto);
+ @include border-radius;
+ max-width: 100vw;
+ padding: 0.5rem;
+ // margin: 0 2rem;
+
+ .device-icon {
+ margin-top: 0.5rem;
+ // @extend .icon-button-middle;
+ }
+
+ .main-info {
+ @include sc($mobile-font-base, #000000);
+ line-height: 2rem;
+ }
+ .secend-info {
+ @include sc($mobile-font-sm, #3e3c36);
+ text-align: start;
+ }
+ .unbind-icon {
+ @extend .icon-button-middle;
+ }
+}
+.mobile-dvtype-index {
+ background-color: #f6f7f8;
+ @include wh(auto, auto);
+ min-height: 100vh;
+ max-width: 100vw;
+ padding: 1rem 1.5rem;
+
+ .mobile-dvtype-box {
+ @extend .mobile-device-box;
+ background-color: #ffffff;
+ margin-bottom: 2rem;
+ }
+ .button-icon {
+ @extend .icon-button-big;
+ vertical-align: -1.5rem;
+ }
+}
+.mobile-device-advice {
+ @include wh(auto, auto);
+ @include full-screen;
+ background-color: #0b0e15;
+
+ .main-icon {
+ width: auto;
+ height: auto;
+ fill: currentColor;
+ overflow: hidden;
+ vertical-align: -0.2rem;
+ }
+ .button-icon {
+ width: 6rem;
+ height: 3rem;
+ fill: currentColor;
+ overflow: hidden;
+ vertical-align: -3rem;
+ }
+ .buy-icon {
+ width: 10rem;
+ height: 3rem;
+ fill: currentColor;
+ overflow: hidden;
+ vertical-align: -3rem;
+ }
+}
+
+.mobile-dvdetail-index {
+ @include full-screen;
+ @include wh(auto, auto);
+ background-color: #f8f9fd;
+
+ .device-detail-info {
+ background-color: #efeff7;
+ padding: 3rem 1rem;
+ padding-top: 3rem;
+ .bracelet-icon {
+ padding-top: 0.4rem;
+ }
+ .state-msg {
+ @include sc($mobile-font-bg, #303030);
+ // font-weight: bold;
+ line-height: 2.5rem;
+ }
+ .secend-msg {
+ @include sc($mobile-font-base, #303030);
+ opacity: 0.8;
+ line-height: 1.4rem;
+ text-align: start;
+ }
+ }
+ .mobile-detail-content {
+ padding: 2rem;
+
+ .detail-box-index {
+ @include border-radius;
+ @include sc($mobile-font-base, #303030);
+ // font-weight: bold;
+ line-height: 2rem;
+
+ background-color: #ffffff;
+ padding: 1rem;
+ margin-bottom: 1rem;
+ }
+ }
+}
+
+.mobile-org-box {
+ @include wh(auto, auto);
+ @include border-radius;
+ max-width: 100vw;
+ padding: 0.5rem;
+ // margin: 0 2rem;
+
+ .device-icon {
+ margin-top: 0.5rem;
+ @extend .icon-button-middle;
+ }
+
+ .main-info {
+ @include sc($mobile-font-base, #000000);
+ line-height: 2rem;
+ }
+ .secend-info {
+ @include sc($mobile-font-sm, #3e3c36);
+ text-align: start;
+ }
+ .unbind-icon {
+ @extend .icon-button-middle;
+ }
+}
+
+.mobile-identity-sign {
+ @include sc($mobile-font-xsm, #d5b870);
+ line-height: 1.5;
+ padding: 0 0.3rem;
+ font-weight: bold;
+ margin-left: 1rem;
+ background-color: black;
+ border-radius: 0.2rem;
+}
+
+.mobile-position-mapinfo {
+ @include sc($mobile-font-md, #303030);
+
+ background-color: white;
+ text-align: start;
+ .icon {
+ @extend .icon-small;
+ vertical-align: -0.2rem;
+ }
+ .content {
+ @include sc($mobile-font-base, #5d9eff);
+ }
+}
+.detail-weektime-btn {
+ color: black;
+ background: black;
+ border-radius: 1rem;
+ background-color: white;
+ &.active,
+ &:hover {
+ background-color: black;
+ }
+}
+
+.mobile-detail-infobox {
+ .title {
+ @include sc($mobile-font-base, #303030);
+ text-align: start;
+ font-weight: bold;
+ padding-left: 1rem;
+ padding-top: 0.5rem;
+ padding-bottom: 0.1rem;
+ }
+ .title-mark {
+ @include sc($mobile-font-xsm, grey);
+ padding-bottom: 0.1rem;
+
+ opacity: 0.5;
+ }
+ .reference {
+ @include sc($mobile-font-xsm, grey);
+ text-align: end;
+ opacity: 0.5;
+ padding-right: 1rem;
+ padding-bottom: 0.1rem;
+ }
+ .eval {
+ @include sc($mobile-font-sm, #777777);
+ padding: 1rem;
+ text-align: start;
+ background-color: white;
+
+ .bigval {
+ font-size: $mobile-font-bg;
+ font-weight: bolder;
+ padding: 0 0.2rem;
+ }
+ }
+ .progress-index {
+ background-color: #f4f5f5;
+ padding-top: 0.3rem;
+ }
+}
+
+/////////////////////////////布局 block////////////
+.sys-padding-block {
+ @include wh(auto, 1rem);
+}
+.layout-title-content {
+ @include wh(auto, 2rem);
+ @include sc($mobile-font-sm, #666666);
+ line-height: 2rem;
+ padding: 0 $mobile-padding-left;
+ background-color: #f8f9fd;
+ text-align: start;
+}
+.sys-text-left {
+ text-align: start;
+}
+.sys-text-right {
+ text-align: end;
+}
+.sys-btn-radius {
+ .van-button {
+ border-radius: 0.5rem;
+ }
+}
+
+.sys-btn-card-allscreen {
+ background-color: #f6f6f6;
+ min-height: 100vh;
+ padding: 1rem;
+ width: 100vw;
+ overflow: hidden;
+}
+.sys-box-index {
+ background-color: white;
+ padding: 1rem;
+ margin: 0.5rem 0;
+ line-height: 1.2;
+ border-radius: 0.2rem;
+ box-shadow: 0 2px 4px 0 rgb(0 0 0 / 10%);
+}
+
+.sys-bottom-border {
+ padding: 0.5rem 0;
+}
+.sys-big-title {
+ @include sc($mobile-font-bger, white);
+ line-height: 2;
+ font-weight: bold;
+}
+.sys-sm-title {
+ @include sc($mobile-font-sm, white);
+ line-height: 2;
+}
+.sys-pc-bgtitle {
+ @include sc($pc-font-sm, white);
+ height: $pc-font-md;
+ line-height: 1.5;
+ text-align: start;
+ padding: 0.1rem 0rem 0.1rem 0.4rem;
+ background-color: #aadcff;
+ box-shadow: 0 2px 4px 0 rgb(0 0 0 / 10%);
+ span {
+ @include sc($pc-font-xsm, white);
+ }
+}
+.sys-my-toash {
+ background-color: #5d9eff;
+ opacity: 0.1;
+}
+
+$progresspadding: 30px;
diff --git a/src/styles/common.scss b/src/styles/common.scss
new file mode 100644
index 0000000..09fcea7
--- /dev/null
+++ b/src/styles/common.scss
@@ -0,0 +1,72 @@
+body {
+ -webkit-font-smoothing: antialiased;
+}
+
+.title-lg {
+ @include ft($font-size-lg, $line-height-base);
+}
+.title-md {
+ @include ft($font-size-md, $line-height-base);
+}
+.font-sm {
+ @include ft($font-size-sm, $line-height-base);
+}
+.font-bold {
+ @include wc($font-weight-base, $font-color-primary);
+}
+
+.margin {
+ margin: 0 auto;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
+
+.hide {
+ display: none;
+}
+
+.show {
+ display: block;
+}
+
+.ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
+::-webkit-scrollbar {
+ width: 0px;
+ height: 0px;
+ background-color: #f5f5f5;
+}
+
+/*定义滚动条轨道 内阴影+圆角*/
+::-webkit-scrollbar-track {
+ -webkit-box-shadow: inset 0 0 1px rgba(0, 0, 0, 0);
+ border-radius: 10px;
+ background-color: #f5f5f5;
+}
+
+/*定义滑块 内阴影+圆角*/
+::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
+ background-color: #555;
+}
+
+* {
+ -webkit-touch-callout: none; /*系统默认菜单被禁用*/
+ -webkit-user-select: none; /*webkit浏览器*/
+ -khtml-user-select: none; /*早期浏览器*/
+ -moz-user-select: none; /*火狐*/
+ -ms-user-select: none; /*IE10*/
+ user-select: none;
+}
diff --git a/src/styles/fixed/fixed_element.scss b/src/styles/fixed/fixed_element.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/styles/mixin.scss b/src/styles/mixin.scss
new file mode 100644
index 0000000..15f8991
--- /dev/null
+++ b/src/styles/mixin.scss
@@ -0,0 +1,199 @@
+//定位全屏
+@mixin allcover {
+ position: absolute;
+ top: 0;
+ right: 0;
+ // top: 0;
+ // left: 0;
+}
+// 定位顶部栏
+@mixin topcover {
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+}
+/*
+子元素排列
+*/
+@mixin contentEnd {
+ position: absolute;
+}
+/*
+划线专区
+*/
+// 设置下划线
+@mixin bottomBoder($width, $color) {
+ border-bottom: $width $color solid;
+}
+/*
+默认margin
+*/
+@mixin lrmg {
+ margin: 0 $line-pc-margin;
+}
+
+@mixin margin($tb, $lr) {
+ margin: $tb $lr;
+}
+@mixin padding($tb, $lr) {
+ padding: $tb $lr;
+}
+// auto适应
+@mixin autowh {
+ width: auto;
+ height: auto;
+ max-width: 100%;
+ max-height: 100%;
+}
+
+//transform上下左右居中
+@mixin ct {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+//定位上下左右居中
+@mixin ctp($width, $height) {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-top: -$height/2;
+ margin-left: -$width/2;
+}
+
+//flex上下左右剧中
+@mixin fct() {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+//定位上下居中
+@mixin tb {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+//flex上下剧中
+@mixin ftb {
+ display: flex;
+ align-items: center;
+}
+
+//定位左右居中
+@mixin lr {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+}
+
+//flex左右剧中
+@mixin flr() {
+ display: flex;
+ justify-content: center;
+}
+
+//宽高
+@mixin wh($width, $height) {
+ width: $width;
+ height: $height;
+}
+
+//字体大小、行高、字体
+@mixin ft($size, $line-height) {
+ font-size: $size;
+ line-height: $line-height;
+}
+
+//字体大小,颜色
+@mixin sc($size, $color) {
+ font-size: $size;
+ color: $color;
+}
+
+//字体粗细,颜色
+@mixin wc($weight, $color) {
+ font-weight: $weight;
+ color: $color;
+}
+
+//flex 布局和 子元素 对其方式
+@mixin fj($type: space-between) {
+ display: flex;
+ justify-content: $type;
+}
+
+//2倍图、3倍图,默认2倍图
+@mixin bg-image($url) {
+ background-image: url("./images/"+$url+"@2x.png");
+
+ @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) {
+ background-image: url("./images/"+$url+"@3x.png");
+ }
+}
+
+//多行超出省略号
+@mixin ellipsis($line: 2, $line-height: 1.2) {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: $line;
+ line-height: $line-height;
+}
+
+@mixin modalbg($color-bg: rgba(0, 0, 0, 0.2)) {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: $color-bg;
+}
+
+@mixin flex($direction: column, $wrap: nowrap) {
+ display: flex;
+ flex-direction: $direction;
+ flex-wrap: $wrap;
+}
+
+@mixin clear() {
+ &:after {
+ content: ".";
+ clear: both;
+ display: block;
+ width: 0;
+ height: 0;
+ visibility: hidden;
+ }
+}
+
+// 宽高度计算
+@mixin m-x($width: 1) {
+ @if unit($width) ==px {
+ margin: {
+ left: $width !important;
+ right: $width !important;
+ }
+ } @else {
+ margin: {
+ left: $width * 10px !important;
+ right: $width * 10px !important;
+ }
+ }
+}
+
+// 有色box 圆角
+
+@mixin border-radius {
+ border-radius: 0.3rem;
+}
+//铺满屏幕
+@mixin full-screen {
+ min-height: 100vh;
+ max-width: 100vw;
+}
diff --git a/src/styles/settings.scss b/src/styles/settings.scss
new file mode 100644
index 0000000..3fbda16
--- /dev/null
+++ b/src/styles/settings.scss
@@ -0,0 +1,18 @@
+$mobile-font-mbger: 2rem;
+$mobile-font-bger: 1.6rem;
+$mobile-font-bg: 1.3rem; //18px
+$mobile-font-md: 1.15rem; //16px
+
+$mobile-font-base: 1rem; //14px
+$mobile-font-sm: 0.85rem; //12px
+$mobile-font-xsm: 0.625rem; //10px
+$mobile-font-xxsm: 0.4rem;
+
+$pc-font-bg: 1.3rem;
+$pc-font-md: 1.15rem;
+
+$pc-font-base: 1rem; //50px
+$pc-font-sm: 0.6rem;
+$pc-font-xsm: 0.48rem;
+$pc-font-xxsm: 0.32rem;
+$pc-font-mini: 0.2rem;
\ No newline at end of file
diff --git a/src/views/index.vue b/src/views/index.vue
new file mode 100644
index 0000000..fdf8e88
--- /dev/null
+++ b/src/views/index.vue
@@ -0,0 +1,12 @@
+
+
+ hello!
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/redirect/index.vue b/src/views/redirect/index.vue
new file mode 100644
index 0000000..4b9e65e
--- /dev/null
+++ b/src/views/redirect/index.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vue.config.js b/vue.config.js
new file mode 100644
index 0000000..6c27abf
--- /dev/null
+++ b/vue.config.js
@@ -0,0 +1,132 @@
+const path = require("path");
+function resolve(dir) {
+ return path.join(__dirname, dir);
+}
+
+const isProduction = process.env.NODE_ENV === "production";
+
+const EXTERNALS = {
+ vue: "Vue",
+ axios: "axios",
+ "element-ui": "ELEMENT",
+ "vue-router": "VueRouter",
+ vuex: "Vuex",
+ vant: "vant",
+ // "vuex-persistedstate": "createPersistedState",
+ lodash: "_",
+ dayjs: "dayjs",
+ echarts: "echarts",
+};
+const CDN_LIST = {
+ css: ["https://cdn.staticfile.org/element-ui/2.15.1/theme-chalk/index.min.css", "https://cdn.staticfile.org/vant/2.12.13/index.min.css"],
+ js: [
+ "https://cdn.staticfile.org/vue/2.6.12/vue.min.js",
+ "https://cdn.staticfile.org/vue-router/3.5.1/vue-router.min.js",
+ "https://cdn.staticfile.org/vuex/3.6.2/vuex.min.js",
+ "https://cdn.staticfile.org/axios/0.21.1/axios.min.js",
+ "https://cdn.staticfile.org/element-ui/2.15.1/index.min.js",
+ "https://cdn.staticfile.org/vant/2.12.13/vant.min.js",
+ // "https://cdn.staticfile.org/vuex-persistedstate/4.0.0-beta.3/vuex-persistedstate.min.js",
+ "https://cdn.staticfile.org/lodash.js/4.17.21/lodash.min.js",
+ "https://cdn.staticfile.org/dayjs/1.10.4/dayjs.min.js",
+ "https://cdn.staticfile.org/echarts/5.1.2/echarts.min.js",
+ ],
+};
+
+module.exports = {
+ publicPath: process.env.VUE_APP_PUBLIC_PATH || "/",
+ devServer: {
+ proxy: {
+ "/apis": {
+ target: "https://api.yyjishu.com/antifraud",
+ changeOrigin: true,
+ pathRewrite: {
+ "^/apis": "",
+ },
+ },
+ },
+ publicPath: process.env.VUE_APP_PUBLIC_PATH || "/",
+ disableHostCheck: !isProduction, // 关闭 host check,方便使用 ngrok 之类的内网转发工具
+ },
+ chainWebpack: (config) => {
+ // 设置一些常用alias
+ config.resolve.alias
+ .set("@", resolve("src"))
+ .set("@assets", resolve("./src/assets"))
+ .set("@components", resolve("src/components"))
+ .set("@styles", resolve("src/styles"))
+ .set("@layout", resolve("src/components/common/layout"))
+ .set("@views", resolve("src/views"));
+
+ config.plugins.delete("prefetch");
+
+ // 压缩图片
+ config.module
+ .rule("images")
+ .use("image-webpack-loader")
+ .loader("image-webpack-loader")
+ .options({ bypassOnDebug: true })
+ .end();
+
+ if (isProduction) {
+ // 通过 html-webpack-plugin 将 cdn 注入到 index.html 之中
+ config.externals(EXTERNALS);
+ config.plugin("html").tap((args) => {
+ args[0].cdn = CDN_LIST;
+ return args;
+ });
+ }
+ },
+ configureWebpack: (config) => {
+ if (isProduction) {
+ // 公共代码抽离
+ config.optimization = {
+ splitChunks: {
+ cacheGroups: {
+ vendor: {
+ chunks: "all",
+ test: /node_modules/,
+ name: "vendor",
+ minChunks: 1,
+ maxInitialRequests: 5,
+ minSize: 0,
+ priority: 100,
+ },
+ common: {
+ chunks: "all",
+ test: /[\\/]src[\\/]js[\\/]/,
+ name: "common",
+ minChunks: 2,
+ maxInitialRequests: 5,
+ minSize: 0,
+ priority: 60,
+ },
+ styles: {
+ name: "styles",
+ test: /\.(sa|sc|c)ss$/,
+ chunks: "all",
+ enforce: true,
+ },
+ runtimeChunk: {
+ name: "manifest",
+ },
+ },
+ },
+ };
+ }
+ },
+ css: {
+ loaderOptions: {
+ scss: {
+ additionalData: `
+ @import "./src/styles/mixin";
+ @import "./src/styles/_var";
+ @import "./src/styles/all.scss";`,
+ },
+ postcss: {
+ plugins: [require("postcss-px2rem")({ remUnit: 32 })],
+ },
+ },
+ },
+ productionSourceMap: false,
+};