@ -0,0 +1,5 @@ |
|||||
|
ENV='development' |
||||
|
# base api |
||||
|
VITE_APP_BASE_URL = 'https://evote.truescloud.com' |
||||
|
VITE_APP_BASE_PRE = '/dev-api' |
||||
|
VITE_APP_BASE_NAME = 'POS' |
||||
@ -0,0 +1,6 @@ |
|||||
|
ENV='production' |
||||
|
# base api |
||||
|
VITE_APP_BASE_URL = 'http://pos-api.lingji.vip' |
||||
|
VITE_APP_BASE_PRE = 'http://pos-api.lingji.vip' |
||||
|
VITE_APP_BASE_NAME = 'POS' |
||||
|
|
||||
@ -0,0 +1,3 @@ |
|||||
|
dist |
||||
|
node_modules |
||||
|
uni_modules |
||||
@ -0,0 +1,146 @@ |
|||||
|
// @see https://eslint.bootcss.com/docs/rules/ |
||||
|
|
||||
|
module.exports = { |
||||
|
env: { |
||||
|
browser: true, |
||||
|
es2021: true, |
||||
|
node: true |
||||
|
}, |
||||
|
globals: { |
||||
|
NodeJS: 'readonly' |
||||
|
}, |
||||
|
/* 指定如何解析语法 */ |
||||
|
parser: 'vue-eslint-parser', |
||||
|
/** 优先级低于 parse 的语法解析配置 */ |
||||
|
parserOptions: { |
||||
|
ecmaVersion: 'latest', |
||||
|
sourceType: 'module', |
||||
|
parser: '@typescript-eslint/parser', |
||||
|
jsxPragma: 'React', |
||||
|
ecmaFeatures: { |
||||
|
jsx: true |
||||
|
} |
||||
|
}, |
||||
|
/* 继承已有的规则 */ |
||||
|
extends: ['eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], |
||||
|
plugins: ['vue', '@typescript-eslint'], |
||||
|
overrides: [ |
||||
|
{ |
||||
|
files: ['*.ts', '*.tsx', '*.vue'], |
||||
|
rules: { |
||||
|
'no-undef': 0 |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
/* |
||||
|
* 'off' 或 0 ==> 关闭规则 |
||||
|
* 'warn' 或 1 ==> 打开的规则作为警告(不影响代码执行) |
||||
|
* 'error' 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) |
||||
|
*/ |
||||
|
rules: { |
||||
|
// typeScript (https://typescript-eslint.io/rules) |
||||
|
'@typescript-eslint/no-unused-vars': [2, { argsIgnorePattern: '^_' }], // 禁止定义未使用的变量 |
||||
|
'@typescript-eslint/prefer-ts-expect-error': 2, // 禁止使用 @ts-ignore |
||||
|
'@typescript-eslint/no-explicit-any': 0, // 禁止使用 any 类型 |
||||
|
'@typescript-eslint/no-non-null-assertion': 0, |
||||
|
'@typescript-eslint/no-namespace': 0, // 禁止使用自定义 TypeScript 模块和命名空间。 |
||||
|
'@typescript-eslint/semi': 0, |
||||
|
'no-prototype-builtins': 0, // 可以使用obj.hasOwnProperty() |
||||
|
'@typescript-eslint/no-var-requires': 0, // 不允许在import 中使用require |
||||
|
'@typescript-eslint/no-empty-function': 2, // 关闭空方法检查 |
||||
|
// eslint-plugin-vue (https://eslint.vuejs.org/rules/) |
||||
|
'vue/multi-word-component-names': 0, // 要求组件名称始终为 “-” 链接的单词 |
||||
|
'vue/script-setup-uses-vars': 2, // 防止<script setup>使用的变量<template>被标记为未使用 |
||||
|
'vue/no-mutating-props': 0, // 不允许组件 prop的改变 |
||||
|
'vue/no-v-html': 0, // 禁止使用 v-html |
||||
|
'vue/no-setup-props-destructure': 0, // 禁止 props 解构传递给 setup |
||||
|
'vue/no-v-model-argument': 0, // 不允许添加要在 v-model 自定义组件中使用的参数 |
||||
|
'vue/component-definition-name-casing': [2, 'PascalCase'], // 强制使用组件定义名称的特定大小写 PascalCase | kebab-case |
||||
|
'vue/attribute-hyphenation': [2, 'always', { ignore: [] }], // 对模板中的自定义组件强制实施属性命名样式 |
||||
|
'vue/no-dupe-keys': [2, { groups: [] }], // 不允许重复字段名称 |
||||
|
'vue/no-dupe-v-else-if': 2, // 不允许 / v-else-if 链中的 v-if 重复条件 |
||||
|
'vue/no-duplicate-attributes': 2, // 禁止属性重复 |
||||
|
'vue/no-ref-as-operand': 2, // 使用ref对象必须.value |
||||
|
'vue/first-attribute-linebreak': [ |
||||
|
2, |
||||
|
{ |
||||
|
singleline: 'ignore', |
||||
|
multiline: 'below' |
||||
|
} |
||||
|
], // 强制设置第一个属性的位置 |
||||
|
|
||||
|
'@typescript-eslint/no-this-alias': [ |
||||
|
'warn', |
||||
|
{ |
||||
|
allowDestructuring: false, // Disallow `const { props, state } = this`; true by default |
||||
|
allowedNames: ['_this'] // this的別名可以为_this |
||||
|
} |
||||
|
], |
||||
|
// eslint(https://eslint.bootcss.com/docs/rules/) |
||||
|
// 'object-curly-spacing': 0, // 在大括号内强制执行一致的间距 |
||||
|
'no-unexpected-multiline': 2, // 禁止空余的多行 |
||||
|
'no-await-in-loop': 2, // 该规则不允许在循环体中使用 await |
||||
|
'no-dupe-else-if': 2, // 禁止 if-else-if 链中的重复条件 |
||||
|
'no-const-assign': 2, // 禁止重新分配 const 变量 |
||||
|
'no-dupe-keys': 2, // 禁止对象字面量中的重复键 |
||||
|
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行 |
||||
|
'no-unused-vars': 0, // 禁止未使用的变量 |
||||
|
'use-isnan': 2, // 检查 NaN 时需要调用 isNaN() |
||||
|
'valid-typeof': 2, // 强制将 typeof 表达式与有效字符串进行比较 |
||||
|
'no-var': 2, // 要求使用 let 或 const 而不是 var |
||||
|
'no-extra-semi': 2, // 禁止不必要的分号 |
||||
|
'no-multi-str': 2, // 禁止多行字符串 |
||||
|
'no-unused-labels': 2, // 禁止未使用的标签 |
||||
|
'array-bracket-newline': [2, 'consistent'], // 在打开数组括号之后和关闭数组括号之前强制换行 |
||||
|
eqeqeq: [2, 'smart'], // 必须使用全等 |
||||
|
'arrow-spacing': 2, // 在箭头函数中的箭头前后强制执行一致的间距 |
||||
|
'function-call-argument-newline': [2, 'consistent'], // 在函数调用的参数之间强制换行 |
||||
|
'no-undef': 2, // 禁止使用未声明的变量,除非在 /*global */ 注释中提及 |
||||
|
complexity: [2, 15], |
||||
|
indent: [2, 4, { SwitchCase: 1 }], |
||||
|
'valid-jsdoc': 0, //jsdoc规则 |
||||
|
'no-console': 0, |
||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, |
||||
|
'no-useless-escape': 0, // 禁止不必要的转义字符 |
||||
|
'@typescript-eslint/ban-types': 0, // 允许使用function 声明函数 |
||||
|
'prettier/prettier': [ |
||||
|
2, |
||||
|
{ |
||||
|
//在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x |
||||
|
arrowParens: 'always', |
||||
|
// 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false |
||||
|
bracketSameLine: false, |
||||
|
// 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) |
||||
|
bracketSpacing: true, |
||||
|
// 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) |
||||
|
embeddedLanguageFormatting: 'auto', |
||||
|
// 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) |
||||
|
htmlWhitespaceSensitivity: 'ignore', |
||||
|
// 一行最多多少个字符 |
||||
|
printWidth: 150, |
||||
|
// 超出打印宽度 (always | never | preserve ) |
||||
|
proseWrap: 'preserve', |
||||
|
// 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) |
||||
|
quoteProps: 'as-needed', |
||||
|
// 指定要使用的解析器,不需要写文件开头的 @prettier |
||||
|
requirePragma: false, |
||||
|
// 不需要自动在文件开头插入 @prettier |
||||
|
insertPragma: false, |
||||
|
// 最后不需要引号 |
||||
|
semi: false, |
||||
|
// 使用单引号 (true:单引号;false:双引号) |
||||
|
singleQuote: true, |
||||
|
// 缩进空格数,默认2个空格 |
||||
|
tabWidth: 4, |
||||
|
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none |
||||
|
trailingComma: 'none', |
||||
|
// 使用制表符而不是空格缩进行 |
||||
|
useTabs: false, |
||||
|
// Vue文件脚本和样式标签缩进 |
||||
|
vueIndentScriptAndStyle: false, |
||||
|
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>" |
||||
|
endOfLine: 'auto' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
.DS_Store |
||||
|
/node_modules |
||||
|
/dist |
||||
|
|
||||
|
# local env files |
||||
|
.env.local |
||||
|
.env.*.local |
||||
|
|
||||
|
# Log files |
||||
|
npm-debug.log* |
||||
|
yarn-debug.log* |
||||
|
yarn-error.log* |
||||
|
|
||||
|
# Editor directories and files |
||||
|
.project |
||||
|
.idea |
||||
|
.vscode |
||||
|
*.suo |
||||
|
*.ntvs* |
||||
|
*.njsproj |
||||
|
*.sln |
||||
|
*.sw* |
||||
|
|
||||
|
/unpackage |
||||
|
.hbuilderx |
||||
|
|
||||
|
package-lock.josn |
||||
|
pnpm-lock.yaml |
||||
|
|
||||
|
/types/auto-imports.d.ts |
||||
@ -0,0 +1,4 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
. "$(dirname -- "$0")/_/husky.sh" |
||||
|
|
||||
|
pnpm run fix |
||||
@ -0,0 +1,8 @@ |
|||||
|
/dist/* |
||||
|
/html/* |
||||
|
.local |
||||
|
/node_modules/** |
||||
|
**/*.svg |
||||
|
**/*.sh |
||||
|
/public/* |
||||
|
/uni_modules/* |
||||
@ -0,0 +1,36 @@ |
|||||
|
module.exports = { |
||||
|
//在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x |
||||
|
arrowParens: 'always', |
||||
|
// 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false |
||||
|
bracketSameLine: false, |
||||
|
// 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) |
||||
|
bracketSpacing: true, |
||||
|
// 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) |
||||
|
embeddedLanguageFormatting: 'auto', |
||||
|
// 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) |
||||
|
htmlWhitespaceSensitivity: 'ignore', |
||||
|
// 一行最多多少个字符 |
||||
|
printWidth: 150, |
||||
|
// 超出打印宽度 (always | never | preserve ) |
||||
|
proseWrap: 'preserve', |
||||
|
// 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) |
||||
|
quoteProps: 'as-needed', |
||||
|
// 指定要使用的解析器,不需要写文件开头的 @prettier |
||||
|
requirePragma: false, |
||||
|
// 不需要自动在文件开头插入 @prettier |
||||
|
insertPragma: false, |
||||
|
// 最后不需要引号 |
||||
|
semi: false, |
||||
|
// 使用单引号 (true:单引号;false:双引号) |
||||
|
singleQuote: true, |
||||
|
// 缩进空格数,默认2个空格 |
||||
|
tabWidth: 4, |
||||
|
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none |
||||
|
trailingComma: 'none', |
||||
|
// 使用制表符而不是空格缩进行 |
||||
|
useTabs: false, |
||||
|
// Vue文件脚本和样式标签缩进 |
||||
|
vueIndentScriptAndStyle: false, |
||||
|
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>" |
||||
|
endOfLine: 'auto' |
||||
|
} |
||||
@ -0,0 +1,85 @@ |
|||||
|
const fs = require('fs') |
||||
|
|
||||
|
const pagesStr = fs.readFileSync('./src/pages.json', 'utf-8'); |
||||
|
const pagesJson = JSON.parse(pagesStr); |
||||
|
// Pages页面
|
||||
|
const Pages = pagesJson.pages.map((i) => { |
||||
|
return { |
||||
|
type: 'Pages', |
||||
|
name: i.name, |
||||
|
path: `/${i.path}`, |
||||
|
title: i.style?.navigationBarTitleText |
||||
|
}; |
||||
|
}); |
||||
|
// 二级页面
|
||||
|
const subPages = pagesJson.subPackages.flatMap((i) => { |
||||
|
return i.pages.map((x) => { |
||||
|
return { |
||||
|
type: 'subPage', |
||||
|
name: x.name, |
||||
|
path: `/${i.root}/${x.path}`, |
||||
|
title: x.style?.navigationBarTitleText |
||||
|
}; |
||||
|
}); |
||||
|
}); |
||||
|
// 当前已有页面
|
||||
|
// const pages = [...Pages, ...subPages];
|
||||
|
// 当前已创建文件
|
||||
|
const filesList = fs.readdirSync('./src/pages'); |
||||
|
const filesSubList = fs.readdirSync('./src/subpackage/pages'); |
||||
|
|
||||
|
// 获取需要新增的页面 =>取差集
|
||||
|
let newPages = Pages.filter((i) => !filesList.includes(i.name)); |
||||
|
const newSubPages = subPages.filter((i) => !filesSubList.includes(i.name)); |
||||
|
|
||||
|
newPages = [...newPages, ...newSubPages] |
||||
|
|
||||
|
// 添加新路由
|
||||
|
function addPages(pages) { |
||||
|
for (const page of pages) { |
||||
|
// 待修改根据path 路径生成
|
||||
|
const { name, title, type } = page; |
||||
|
let dirPath = '' |
||||
|
switch (type) { |
||||
|
case 'Pages': |
||||
|
// 主包
|
||||
|
dirPath = `./src/pages/${name}`; |
||||
|
break; |
||||
|
case 'subPage': |
||||
|
// 分包
|
||||
|
dirPath = `./src/subpackage/pages/${name}`; |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
// if (name.toLowerCase().indexOf("list") != -1) {
|
||||
|
// console.log(22222222);
|
||||
|
|
||||
|
// } else {
|
||||
|
// console.log(33333333);
|
||||
|
// }
|
||||
|
|
||||
|
// return
|
||||
|
fs.mkdirSync(dirPath); |
||||
|
const filePath = `${dirPath}/${name}.vue`; |
||||
|
const createStream = fs.createWriteStream(filePath); |
||||
|
|
||||
|
const template = |
||||
|
`<script setup lang="ts">
|
||||
|
import HeaderXcx from '@/components/Header/HeaderXcx.vue' |
||||
|
</script> |
||||
|
<template> |
||||
|
<view class=""> |
||||
|
<HeaderXcx :leftTxt="'标题'" :textColor="'#fff'" :goBack="false"></HeaderXcx> |
||||
|
${title} |
||||
|
</view> |
||||
|
</template> |
||||
|
<style lang="scss" scoped></style>`;
|
||||
|
createStream.write(template); |
||||
|
createStream.end(); |
||||
|
console.log('\x1B[34m', `pages ${name} created successfully.`); |
||||
|
} |
||||
|
console.log('\x1B[32m%s\x1B[39m', '\n All files are created successfully.\n'); |
||||
|
} |
||||
|
|
||||
|
addPages(newPages); |
||||
@ -0,0 +1,4 @@ |
|||||
|
if (!/pnpm/.test(process.env.npm_execpath || '')) { |
||||
|
console.warn(`\u001b[33mThis repository must using pnpm as the package manager ` + ` for scripts to work properly.\u001b[39m\n`) |
||||
|
process.exit(1) |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
|
||||
|
<head> |
||||
|
<meta charset="UTF-8" /> |
||||
|
<script> |
||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || |
||||
|
CSS.supports('top: constant(a)')) |
||||
|
document.write( |
||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + |
||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />') |
||||
|
</script> |
||||
|
<title></title> |
||||
|
<!--preload-links--> |
||||
|
<!--app-context--> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<view id="app"><!--app-html--></view> |
||||
|
<script type="module" src="/src/main.ts"></script> |
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
@ -0,0 +1,100 @@ |
|||||
|
{ |
||||
|
"name": "uni-preset-vue", |
||||
|
"version": "0.0.0", |
||||
|
"scripts": { |
||||
|
"dev:app": "uni -p app", |
||||
|
"dev:app-android": "uni -p app-android", |
||||
|
"dev:app-ios": "uni -p app-ios", |
||||
|
"dev:custom": "uni -p", |
||||
|
"dev:h5": "uni", |
||||
|
"dev:h5:prop": "uni --mode=production", |
||||
|
"dev:h5:ssr": "uni --ssr", |
||||
|
"dev:mp-alipay": "uni -p mp-alipay", |
||||
|
"dev:mp-baidu": "uni -p mp-baidu", |
||||
|
"dev:mp-jd": "uni -p mp-jd", |
||||
|
"dev:mp-kuaishou": "uni -p mp-kuaishou", |
||||
|
"dev:mp-lark": "uni -p mp-lark", |
||||
|
"dev:mp-qq": "uni -p mp-qq", |
||||
|
"dev:mp-toutiao": "uni -p mp-toutiao", |
||||
|
"dev:mp-weixin": "uni -p mp-weixin", |
||||
|
"dev:quickapp-webview": "uni -p quickapp-webview", |
||||
|
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei", |
||||
|
"dev:quickapp-webview-union": "uni -p quickapp-webview-union", |
||||
|
"build:app": "uni build -p app", |
||||
|
"build:app-android": "uni build -p app-android", |
||||
|
"build:app-ios": "uni build -p app-ios", |
||||
|
"build:custom": "uni build -p", |
||||
|
"build:h5": "uni build", |
||||
|
"build:h5:ssr": "uni build --ssr", |
||||
|
"build:mp-alipay": "uni build -p mp-alipay", |
||||
|
"build:mp-baidu": "uni build -p mp-baidu", |
||||
|
"build:mp-jd": "uni build -p mp-jd", |
||||
|
"build:mp-kuaishou": "uni build -p mp-kuaishou", |
||||
|
"build:mp-lark": "uni build -p mp-lark", |
||||
|
"build:mp-qq": "uni build -p mp-qq", |
||||
|
"build:mp-toutiao": "uni build -p mp-toutiao", |
||||
|
"build:mp-weixin": "uni build -p mp-weixin", |
||||
|
"build:quickapp-webview": "uni build -p quickapp-webview", |
||||
|
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei", |
||||
|
"build:quickapp-webview-union": "uni build -p quickapp-webview-union", |
||||
|
"type-check": "vue-tsc --noEmit", |
||||
|
"add": "node ./auto/addPage.ts", |
||||
|
"preinstall": "node ./auto/preinstall.js", |
||||
|
"lint": "eslint --ext .ts,.js,.vue ./src", |
||||
|
"fix": "eslint --fix --ext .ts,.js,.vue ./src", |
||||
|
"prepare": "husky install", |
||||
|
"rm": "rm -rf node_modules package-lock.json pnpm-lock.yaml && pnpm install" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@dcloudio/uni-app": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-app-plus": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-components": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-h5": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-jd": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-lark": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-qq": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-mp-xhs": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3081220230802001", |
||||
|
"@qiun/ucharts": "2.5.0-20230101", |
||||
|
"animate.css": "^4.1.1", |
||||
|
"echarts": "^5.5.0", |
||||
|
"pinia": "2.0.36", |
||||
|
"sass": "^1.63.2", |
||||
|
"uview-plus": "^3.4.9", |
||||
|
"vue": "^3.2.45", |
||||
|
"vue-i18n": "^9.1.9" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"@babel/eslint-parser": "^7.22.9", |
||||
|
"@dcloudio/types": "^3.3.2", |
||||
|
"@dcloudio/uni-automator": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3081220230802001", |
||||
|
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3081220230802001", |
||||
|
"@typescript-eslint/eslint-plugin": "^6.2.1", |
||||
|
"@typescript-eslint/parser": "^6.2.1", |
||||
|
"@vue/tsconfig": "^0.1.3", |
||||
|
"@vueuse/core": "^10.3.0", |
||||
|
"eslint": "^8.46.0", |
||||
|
"eslint-config-prettier": "^8.9.0", |
||||
|
"eslint-plugin-import": "^2.28.0", |
||||
|
"eslint-plugin-node": "^11.1.0", |
||||
|
"eslint-plugin-prettier": "^5.0.0", |
||||
|
"eslint-plugin-vue": "^9.16.1", |
||||
|
"feng-uniapp-exploit": "^1.0.2", |
||||
|
"husky": "^8.0.0", |
||||
|
"pinia-plugin-unistorage": "^0.0.17", |
||||
|
"prettier": "^3.0.0", |
||||
|
"sass-loader": "^10.4.1", |
||||
|
"typescript": "^4.9.4", |
||||
|
"unplugin-auto-import": "^0.16.6", |
||||
|
"unplugin-vue-components": "^0.25.1", |
||||
|
"vite": "4.0.3", |
||||
|
"vue-tsc": "^1.0.24" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
<template> |
||||
|
<view id="app"> |
||||
|
<router-view></router-view> |
||||
|
</view> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
// import routingIntercept from '@/permission' |
||||
|
|
||||
|
onLaunch(() => { |
||||
|
// routingIntercept() |
||||
|
}) |
||||
|
onShow(() => { |
||||
|
console.log('App Show') |
||||
|
}) |
||||
|
onHide(() => { |
||||
|
console.log('App Hide') |
||||
|
}) |
||||
|
// 全局变量 |
||||
|
// provide('globalObj', <globalObjInt>{ |
||||
|
// // 公用跳转方法 |
||||
|
// goToPage |
||||
|
// }); |
||||
|
// // 引入静态资源 |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */ |
||||
|
@import 'uview-plus/index.scss'; |
||||
|
</style> |
||||
@ -0,0 +1,25 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export function getVoteList(data: pageType) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_list', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getVoteDetail(data: { id: number }) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_result_detail', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getVoteResult(data: pageType) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_result', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export function getOpenid(data: { code: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/openid', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getMobile(data: { code: string; openid: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/mobile', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getAdminPhone() { |
||||
|
return request.http({ |
||||
|
url: '/api/admin_mobile', |
||||
|
method: 'GET' |
||||
|
}) |
||||
|
} |
||||
|
//用户签到
|
||||
|
export function getSign(data: { meetId: string; openid: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/sign', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//扫码时手机号获取用户信息
|
||||
|
export function getmemberMobileGet(data: { meetId: string; openid: string; mobile: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile_get', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export interface listType { |
||||
|
name: string |
||||
|
age: number |
||||
|
sex: number |
||||
|
nation: string |
||||
|
mobile: string |
||||
|
position: string |
||||
|
work_unit: string |
||||
|
} |
||||
|
|
||||
|
export interface dateListtype extends listType { |
||||
|
id: number |
||||
|
} |
||||
|
|
||||
|
export function infoForOpenid(data: { openid: string; mobile: string ; meetId: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile_get', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 手机号获取用户信息
|
||||
|
export function getMember_mobile(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function list(data: { name: string, meetId: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_name', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function update(data: { [n: string]: string }, openid: string) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_update', |
||||
|
data: Object.assign(data, { openid }) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function bind(data: { id: number; openid: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/name_sub', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function add(data: listType) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_add', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
// 获取投票选举(正在进行)
|
||||
|
export function getVoteprogress(id: string) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_progress?meetId='+ id, |
||||
|
method: 'GET' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//用户投票
|
||||
|
export function voteMember(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_member', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取我的选举
|
||||
|
export function getMyvote(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/my_vote', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 手机号获取用户信息
|
||||
|
export function getMember_mobile(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 判断用户是否签到
|
||||
|
export function getIs_sign(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/is_sign', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
export const Prefix = 'Election_' |
||||
|
|
||||
|
export const getPrefixName = (name: string) => { |
||||
|
return Prefix + name |
||||
|
} |
||||
|
|
||||
|
export function getAuthorization() { |
||||
|
return uni.getStorageSync(getPrefixName('user')) |
||||
|
} |
||||
|
|
||||
|
export function removeAuthorization() { |
||||
|
return uni.removeStorageSync(getPrefixName('user')) |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
import { createSSRApp } from 'vue' |
||||
|
import App from './App.vue' |
||||
|
|
||||
|
import uviewPlus from 'uview-plus' |
||||
|
import fengUniappExploit from 'feng-uniapp-exploit' |
||||
|
|
||||
|
import store from './store' |
||||
|
|
||||
|
export function createApp() { |
||||
|
const app = createSSRApp(App) |
||||
|
app.use(uviewPlus) |
||||
|
app.use(fengUniappExploit) |
||||
|
app.use(store) |
||||
|
|
||||
|
return { app } |
||||
|
} |
||||
@ -0,0 +1,131 @@ |
|||||
|
{ |
||||
|
"name" : "惠企通", |
||||
|
"appid" : "__UNI__4CC99EE", |
||||
|
"description" : "v3+ts+uniapp模版", |
||||
|
"versionName" : "1.0.68", |
||||
|
"versionCode" : 168, |
||||
|
"transformPx" : false, |
||||
|
/* 5+App特有相关 */ |
||||
|
"app-plus" : { |
||||
|
"usingComponents" : true, |
||||
|
"nvueStyleCompiler" : "uni-app", |
||||
|
"compilerVersion" : 3, |
||||
|
"splashscreen" : { |
||||
|
"alwaysShowBeforeRender" : true, |
||||
|
"waiting" : true, |
||||
|
"autoclose" : true, |
||||
|
"delay" : 0 |
||||
|
}, |
||||
|
"compatible" : { |
||||
|
"ignoreVersion" : true |
||||
|
}, |
||||
|
/* 模块配置 */ |
||||
|
"modules" : { |
||||
|
"Barcode" : {}, |
||||
|
"Camera" : {}, |
||||
|
"VideoPlayer" : {}, |
||||
|
"Share" : {}, |
||||
|
"Geolocation" : {}, |
||||
|
"Maps" : {} |
||||
|
}, |
||||
|
/* 应用发布信息 */ |
||||
|
"distribute" : { |
||||
|
/* android打包配置 */ |
||||
|
"android" : { |
||||
|
"permissions" : [ |
||||
|
"<uses-feature android:name=\"android.hardware.camera\"/>", |
||||
|
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
||||
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
||||
|
], |
||||
|
"minSdkVersion" : 21 |
||||
|
}, |
||||
|
/* ios打包配置 */ |
||||
|
"ios" : { |
||||
|
"dSYMs" : false |
||||
|
}, |
||||
|
/* SDK配置 */ |
||||
|
"sdkConfigs" : { |
||||
|
"ad" : {}, |
||||
|
"share" : { |
||||
|
"weixin" : { |
||||
|
"appid" : "wx5d1a07b75bd48225", |
||||
|
"UniversalLinks" : "" |
||||
|
} |
||||
|
}, |
||||
|
"geolocation" : { |
||||
|
"amap" : { |
||||
|
"name" : "amap_18648278829CcsBXVUm1", |
||||
|
"__platform__" : [ "ios", "android" ], |
||||
|
"appkey_ios" : "37180416cb95db05dc9639e616655a7a", |
||||
|
"appkey_android" : "37180416cb95db05dc9639e616655a7a" |
||||
|
} |
||||
|
}, |
||||
|
"maps" : { |
||||
|
"amap" : { |
||||
|
"name" : "amap_18648278829CcsBXVUm1", |
||||
|
"appkey_ios" : "37180416cb95db05dc9639e616655a7a", |
||||
|
"appkey_android" : "37180416cb95db05dc9639e616655a7a" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
"icons" : { |
||||
|
"android" : { |
||||
|
"hdpi" : "src/static/logo.png", |
||||
|
"xhdpi" : "src/static/logo.png", |
||||
|
"xxhdpi" : "src/static/logo.png", |
||||
|
"xxxhdpi" : "src/static/logo.png" |
||||
|
} |
||||
|
}, |
||||
|
"splashscreen" : { |
||||
|
"iosStyle" : "common", |
||||
|
"androidStyle" : "default", |
||||
|
"android" : { |
||||
|
"hdpi" : "", |
||||
|
"xhdpi" : "", |
||||
|
"xxhdpi" : "" |
||||
|
}, |
||||
|
"ios" : { |
||||
|
"storyboard" : "C:/Users/Lenovo/Desktop/CustomStoryboard.zip" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
/* 快应用特有相关 */ |
||||
|
"quickapp" : {}, |
||||
|
/* 小程序特有相关 */ |
||||
|
"mp-weixin" : { |
||||
|
"appid" : "wx4f9dae5cc37dd9f4", |
||||
|
"setting" : { |
||||
|
"urlCheck" : false, |
||||
|
"es6" : true, |
||||
|
"postcss" : false, |
||||
|
"minified" : true |
||||
|
}, |
||||
|
"usingComponents" : true |
||||
|
}, |
||||
|
"mp-alipay" : { |
||||
|
"usingComponents" : true |
||||
|
}, |
||||
|
"mp-baidu" : { |
||||
|
"usingComponents" : true |
||||
|
}, |
||||
|
"mp-toutiao" : { |
||||
|
"usingComponents" : true |
||||
|
}, |
||||
|
"uniStatistics" : { |
||||
|
"enable" : false |
||||
|
}, |
||||
|
"vueVersion" : "3" |
||||
|
} |
||||
@ -0,0 +1,85 @@ |
|||||
|
{ |
||||
|
"easycom": { |
||||
|
"autoscan": true, |
||||
|
"custom": { |
||||
|
"^ex-(.*)": "feng-uniapp-exploit/components/ex-$1/ex-$1.vue", |
||||
|
"^u-(.*)": "uview-plus/components/u-$1/u-$1.vue" |
||||
|
} |
||||
|
}, |
||||
|
"pages": [ |
||||
|
{ |
||||
|
"path": "pages/index/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "首页", |
||||
|
"enablePullDownRefresh": true |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"path": "pages/memberCenter/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "会员中心", |
||||
|
"enablePullDownRefresh": true |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"path": "pages/learningCenter/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "学习中心", |
||||
|
"enablePullDownRefresh": true |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"name": "user", |
||||
|
"path": "pages/mine/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "个人中心", |
||||
|
"enablePullDownRefresh": true |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"path": "pages/login/login", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "登录", |
||||
|
"enablePullDownRefresh": false, |
||||
|
"navigationStyle": "custom" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"globalStyle": { |
||||
|
"navigationBarTextStyle": "white", |
||||
|
"navigationBarBackgroundColor": "#F1F3F9", |
||||
|
"backgroundColor": "#F8F8F8" |
||||
|
}, |
||||
|
"tabBar": { |
||||
|
"color": "#9CA3AF", |
||||
|
"selectedColor": "#2563EB", |
||||
|
"borderStyle": "white", |
||||
|
"backgroundColor": "#FFFFFF", |
||||
|
"list": [ |
||||
|
{ |
||||
|
"pagePath": "pages/index/index", |
||||
|
"iconPath": "static/tabbar/index.png", |
||||
|
"selectedIconPath": "static/tabbar/index_select.png", |
||||
|
"text": "首页" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/memberCenter/index", |
||||
|
"iconPath": "static/tabbar/hyzx.png", |
||||
|
"selectedIconPath": "static/tabbar/hyzx_select.png", |
||||
|
"text": "会员中心" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/learningCenter/index", |
||||
|
"iconPath": "static/tabbar/xxzx.png", |
||||
|
"selectedIconPath": "static/tabbar/xxzx_select.png", |
||||
|
"text": "学习中心" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/mine/index", |
||||
|
"iconPath": "static/tabbar/grzx.png", |
||||
|
"selectedIconPath": "static/tabbar/grzx_select.png", |
||||
|
"text": "个人中心" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,283 @@ |
|||||
|
<template> |
||||
|
<view class="container"> |
||||
|
<scroll-view v-if="electionList.length !== 0" class="scroll-view" scroll-y @scrolltolower="loadMore" :show-scrollbar="false"> |
||||
|
<view v-for="(item, index) in electionList" :key="index" class="election-item"> |
||||
|
<view class="year-title"> |
||||
|
<view class="headpart"> |
||||
|
<text class="title">{{ item.vote_title }}</text> |
||||
|
<view |
||||
|
class="type" |
||||
|
:style=" |
||||
|
item.vote_title == 1 |
||||
|
? 'background: #DBEAFE;color: #3B82F6;' |
||||
|
: item.vote_title == 2 |
||||
|
? 'background: #DCFCE7;color: #10B981' |
||||
|
: 'background: #F3F4F6;color: #4B5563' |
||||
|
" |
||||
|
> |
||||
|
{{ item.status == 1 ? '未开始' : item.status == 2 ? '进行中' : '已结束' }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between" style="display: flex" v-show="expandedStates[index]"> |
||||
|
<view style="display: grid"> |
||||
|
<view |
||||
|
v-for="(candidate, cIndex) in item.candidate.slice(0, expandedStates[index] ? cIndex : 1)" |
||||
|
:key="cIndex" |
||||
|
class="candidate-item" |
||||
|
> |
||||
|
<view class="info-section"> |
||||
|
<view style="display: flex; align-items: center"> |
||||
|
<img style="width: 96rpx; height: 96rpx; border-radius: 50%" :src="candidate.photo" alt="" /> |
||||
|
<view style="margin-left: 24rpx; display: grid"> |
||||
|
<text class="name">{{ candidate.name }}</text> |
||||
|
<text class="college">{{ candidate.position }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view style="display: flex; margin-top: 24rpx; font-family: Roboto; font-size: 28rpx; color: #4b5563"> |
||||
|
我的选择: |
||||
|
<view :class="['choice-tag', choiceClass(candidate.vote_result)]"> |
||||
|
{{ choiceText(candidate.vote_result) }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="expand-btn" @click="toggleExpand(index)"> |
||||
|
<text :class="['arrow', expandedStates[index] ? 'up' : 'down']"></text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
<view v-else> |
||||
|
<ex-empty :height="55" :tips="'暂无数据~'" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, watch } from 'vue' |
||||
|
import { getMyvote } from '../../api/votingElection' |
||||
|
import useUserStore from '@/store/user' |
||||
|
const userStore = useUserStore() |
||||
|
|
||||
|
const electionList = ref([]) |
||||
|
const page = ref(1) |
||||
|
const pageSize = ref(10) |
||||
|
const loading = ref(false) |
||||
|
const noMoreData = ref(false) |
||||
|
|
||||
|
// 展开状态管理 |
||||
|
const expandedStates = ref([]) |
||||
|
watch( |
||||
|
() => electionList.value, |
||||
|
(newVal) => { |
||||
|
expandedStates.value = newVal.map(() => false) |
||||
|
}, |
||||
|
{ |
||||
|
immediate: true |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
const toggleExpand = (index) => { |
||||
|
expandedStates.value[index] = !expandedStates.value[index] |
||||
|
} |
||||
|
|
||||
|
const choiceClass = (choice) => { |
||||
|
switch (choice) { |
||||
|
case 1: |
||||
|
return 'agree' |
||||
|
case 2: |
||||
|
return 'oppose' |
||||
|
case 3: |
||||
|
return 'abstain' |
||||
|
default: |
||||
|
return '' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const choiceText = (choice) => { |
||||
|
return ( |
||||
|
{ |
||||
|
1: '同意', |
||||
|
2: '反对', |
||||
|
3: '弃权' |
||||
|
}[choice] || '' |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
// 获取数据 |
||||
|
const getList = async () => { |
||||
|
try { |
||||
|
loading.value = true |
||||
|
|
||||
|
let param = { |
||||
|
openid: userStore.openId, |
||||
|
page: page.value, |
||||
|
limit: pageSize.value |
||||
|
} |
||||
|
// 模拟接口请求(替换为你的真实接口) |
||||
|
const mockData = await getMyvote(param) |
||||
|
|
||||
|
// 处理数据 |
||||
|
electionList.value = [...electionList.value, ...mockData.data.data] |
||||
|
// electionList.value.push(mockData) |
||||
|
|
||||
|
// 判断是否还有数据 |
||||
|
noMoreData.value = mockData.data.data.length < pageSize.value |
||||
|
} finally { |
||||
|
loading.value = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 加载更多 |
||||
|
const loadMore = () => { |
||||
|
if (loading.value || noMoreData.value) return |
||||
|
page.value += 1 |
||||
|
getList() |
||||
|
} |
||||
|
|
||||
|
onShow(() => { |
||||
|
electionList.value = [] |
||||
|
getList() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.container { |
||||
|
padding: 20rpx; |
||||
|
background-color: #f9fafb; |
||||
|
height: 100vh; |
||||
|
} |
||||
|
|
||||
|
.election-item { |
||||
|
margin-bottom: 30rpx; |
||||
|
padding: 34rpx; |
||||
|
border-radius: 24rpx; |
||||
|
background: linear-gradient(0deg, rgba(0, 0, 0, 0.001), rgba(0, 0, 0, 0.001)), #ffffff; |
||||
|
box-sizing: border-box; |
||||
|
border: 2rpx solid #f3f4f6; |
||||
|
box-shadow: 0rpx 2rpx 4rpx 0rpx rgba(0, 0, 0, 0.05); |
||||
|
} |
||||
|
|
||||
|
.year-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333; |
||||
|
|
||||
|
.headpart { |
||||
|
width: 100%; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
|
||||
|
.title { |
||||
|
font-family: Roboto; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 800; |
||||
|
letter-spacing: normal; |
||||
|
color: #000000; |
||||
|
} |
||||
|
|
||||
|
.type { |
||||
|
font-family: Roboto; |
||||
|
font-size: 24rpx; |
||||
|
font-weight: normal; |
||||
|
/* 自动布局 */ |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
padding: 4rpx 16rpx; |
||||
|
gap: 0rpx 20rpx; |
||||
|
flex-wrap: wrap; |
||||
|
align-content: flex-start; |
||||
|
border-radius: 24rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.candidate-item { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 20rpx 0; |
||||
|
} |
||||
|
|
||||
|
.info-section { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.name { |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 500; |
||||
|
letter-spacing: normal; |
||||
|
color: #000000; |
||||
|
} |
||||
|
|
||||
|
.college { |
||||
|
font-family: Roboto; |
||||
|
font-size: 24rpx; |
||||
|
font-weight: normal; |
||||
|
letter-spacing: normal; |
||||
|
color: #6b7280; |
||||
|
} |
||||
|
|
||||
|
.choice-tag { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: normal; |
||||
|
} |
||||
|
|
||||
|
.agree { |
||||
|
color: #3b82f6; |
||||
|
} |
||||
|
|
||||
|
.oppose { |
||||
|
color: #f44336; |
||||
|
} |
||||
|
|
||||
|
.abstain { |
||||
|
color: #9ca3af; |
||||
|
} |
||||
|
|
||||
|
.year-title { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.expand-btn { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
color: #666; |
||||
|
font-size: 26rpx; |
||||
|
padding: 10rpx 20rpx; |
||||
|
} |
||||
|
|
||||
|
.arrow { |
||||
|
display: inline-block; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
margin-left: 10rpx; |
||||
|
border-left: 10rpx solid transparent; |
||||
|
border-right: 10rpx solid transparent; |
||||
|
} |
||||
|
|
||||
|
.down { |
||||
|
border-top: 15rpx solid #999; |
||||
|
} |
||||
|
|
||||
|
.up { |
||||
|
border-bottom: 15rpx solid #999; |
||||
|
} |
||||
|
|
||||
|
/* 优化候选人项间距 */ |
||||
|
.candidate-item:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,27 @@ |
|||||
|
<template> |
||||
|
<view class="container"> |
||||
|
|
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, watch } from 'vue' |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
onShow(() => { |
||||
|
electionList.value = [] |
||||
|
getList() |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.container { |
||||
|
padding: 20rpx; |
||||
|
background-color: #f9fafb; |
||||
|
height: 100vh; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,111 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { debounce } from 'feng-uniapp-exploit/utils/index' |
||||
|
import { getMobile, getSign} from '@/api/login' |
||||
|
|
||||
|
import useUserStore from '@/store/user' |
||||
|
const userStore = useUserStore() |
||||
|
|
||||
|
const loginCode = ref('') |
||||
|
|
||||
|
// 获取微信登录 code |
||||
|
const getLoginCode = async () : Promise<string> => { |
||||
|
try { |
||||
|
const res = await uni.login({ provider: 'weixin' }) |
||||
|
loginCode.value = res.code |
||||
|
return res.code |
||||
|
} catch (error) { |
||||
|
console.error('获取登录code失败:', error) |
||||
|
throw error |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 处理获取手机号 |
||||
|
|
||||
|
interface phoneEvent { |
||||
|
detail : { errMsg : string; iv : string; encryptedData : string; code : string } |
||||
|
} |
||||
|
const onGetPhoneNumber = debounce(async (e : phoneEvent) => { |
||||
|
if (e.detail.errMsg.includes('fail')) { |
||||
|
uni.showToast({ title: '用户拒绝授权', icon: 'none' }) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
if (!loginCode.value) { |
||||
|
await getLoginCode() |
||||
|
} |
||||
|
|
||||
|
if (!userStore.openId) { |
||||
|
await userStore.getopenid({ code: loginCode.value }) |
||||
|
} |
||||
|
|
||||
|
getMobile({ openid: userStore.openId, code: e.detail.code }) |
||||
|
.then((res) => { |
||||
|
const { data: phone } = res as { data : string } |
||||
|
|
||||
|
userStore.mobile = phone |
||||
|
|
||||
|
userStore.getUserInfo() |
||||
|
|
||||
|
onLoginSuccess() |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
uni.showToast({ title: '登录失败!', icon: 'none' }) |
||||
|
}) |
||||
|
} catch (error) { |
||||
|
uni.showToast({ title: '登录失败', icon: 'none' }) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
const onLoginSuccess = () => { |
||||
|
uni.showToast({ |
||||
|
title: '登录成功', |
||||
|
icon: 'none', |
||||
|
success: () => { |
||||
|
setTimeout(() => { |
||||
|
userStore.showtoast = false |
||||
|
|
||||
|
uni.reLaunch({ url: '/pages/votingElection/index?meetId=' + userStore.meetId }) |
||||
|
}, 1000) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
onLoad((options : any) => { |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
onShow(() => { |
||||
|
// if (userStore.mobile) { |
||||
|
// onLoginSuccess() |
||||
|
// } |
||||
|
}) |
||||
|
</script> |
||||
|
<template> |
||||
|
<view class="login"> |
||||
|
<image class="logo-img" src="@/static/logo.png" mode="widthFix" /> |
||||
|
|
||||
|
<view class="btn_box"> |
||||
|
<u-button @getphonenumber="onGetPhoneNumber" text="请签到后进行投票" icon-color="#fff" open-type="getPhoneNumber" |
||||
|
color="linear-gradient(270deg, rgba(232, 123, 7, 1) 0%, rgba(247, 205, 77, 1) 100%)" shape="circle" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.login { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
overflow: hidden; |
||||
|
position: relative; |
||||
|
text-align: center; |
||||
|
box-sizing: border-box; |
||||
|
padding: 500rpx 30rpx 0; |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.logo-img { |
||||
|
width: 220rpx; |
||||
|
margin-bottom: 60rpx; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,203 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { getVoteResult } from '@/api/common' |
||||
|
const navto = (url: string, params = {}) => uni.$util.goToPage({ url, params }) |
||||
|
const doSearch = (formData: { page: number; limit: number }, onSuccess: Function) => { |
||||
|
getVoteResult(formData).then((res) => { |
||||
|
const { data } = res as { data: { data: any; total: number } } |
||||
|
onSuccess({ data }) |
||||
|
}) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<view class="electionList"> |
||||
|
<ex-list ref="reListRef" custom-list-type="scroll" :on-form-search="doSearch"> |
||||
|
<template v-slot="{ row, index }"> |
||||
|
<view class="items" :uid="'items' + index"> |
||||
|
<view class="flex"> |
||||
|
<view class="flex1"> |
||||
|
<view class="flex-center-start"> |
||||
|
<text class="text-ellipsis title">{{ row.title }}</text> |
||||
|
<text class="status b" v-if="row.status === 2">进行中</text> |
||||
|
<text class="status f" v-else-if="row.status === 1">未开始</text> |
||||
|
<text class="status e" v-else>已结束</text> |
||||
|
</view> |
||||
|
<view class="time">{{ `投票时间:${row.start_time} 至 ${row.end_time}` }}</view> |
||||
|
</view> |
||||
|
<view :class="{ arrow: true, active: row.showInfo }" @click="row.showInfo = !row.showInfo"> |
||||
|
<u-icon name="arrow-down" color="#9CA3AF" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="info" v-if="row.showInfo"> |
||||
|
<view class="flex info-items" v-for="(v, k) of row.candidate" :key="k"> |
||||
|
<view class="head"> |
||||
|
<image :src="v.photo" mode="aspectFill" /> |
||||
|
</view> |
||||
|
<view class="content flex1"> |
||||
|
<view class="name flex-center-start"> |
||||
|
<text>{{ v.name }}</text> |
||||
|
<text class="status" v-if="v.vote_result == 1">当选</text> |
||||
|
<text class="status un" v-else>未当选</text> |
||||
|
</view> |
||||
|
<view class="votes">得票数:{{ v.agree_num }}</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="progress"> |
||||
|
<u-line-progress :percentage="v.agree_percent" height="8rpx" active-color="#2563EB" :show-text="false" /> |
||||
|
<view class="progress-text">{{ v.agree_percent }}%</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="info-bts" v-if="row.status === 3" @click.stop="navto('pages/electionList/info', { id: row.id })"> |
||||
|
查看投票详情 |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
</ex-list> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.electionList { |
||||
|
width: 100%; |
||||
|
min-height: 100vh; |
||||
|
box-sizing: border-box; |
||||
|
padding: 32rpx; |
||||
|
background-color: #f9fafb; |
||||
|
|
||||
|
.items { |
||||
|
padding: 32rpx; |
||||
|
border-radius: 12px; |
||||
|
background: linear-gradient(0deg, rgba(0, 0, 0, 0.001), rgba(0, 0, 0, 0.001)), #ffffff; |
||||
|
box-sizing: border-box; |
||||
|
border: 1px solid #f3f4f6; |
||||
|
box-shadow: |
||||
|
0px 1px 2px -1px rgba(0, 0, 0, 0.1), |
||||
|
0px 1px 3px 0px rgba(0, 0, 0, 0.1); |
||||
|
margin-bottom: 32rpx; |
||||
|
|
||||
|
.text-ellipsis { |
||||
|
overflow: hidden; |
||||
|
white-space: noraml; |
||||
|
text-overflow: ellipsis; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
color: #000; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 500; |
||||
|
line-height: 48rpx; |
||||
|
} |
||||
|
|
||||
|
.status { |
||||
|
font-size: 24rpx; |
||||
|
border-radius: 20rpx; |
||||
|
padding: 0 16rpx; |
||||
|
margin-left: 16rpx; |
||||
|
white-space: nowrap; |
||||
|
|
||||
|
&.b { |
||||
|
color: #fff; |
||||
|
background-color: #2563eb; |
||||
|
} |
||||
|
|
||||
|
&.f { |
||||
|
color: #6b7280; |
||||
|
background-color: #e5e7eb; |
||||
|
} |
||||
|
|
||||
|
&.e { |
||||
|
color: #fff; |
||||
|
background-color: #ef4444; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.time { |
||||
|
padding-top: 8rpx; |
||||
|
color: #6b7280; |
||||
|
line-height: 40rpx; |
||||
|
font-size: 28rpx; |
||||
|
} |
||||
|
|
||||
|
.arrow { |
||||
|
transition: 0.3s all ease-in; |
||||
|
|
||||
|
&.active { |
||||
|
transform: rotateZ(180deg); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.info { |
||||
|
&-items { |
||||
|
margin-top: 32rpx; |
||||
|
|
||||
|
.head { |
||||
|
width: 96rpx; |
||||
|
height: 96rpx; |
||||
|
border-radius: 50%; |
||||
|
overflow: hidden; |
||||
|
background-color: #6b7280; |
||||
|
margin-right: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
height: min-content; |
||||
|
|
||||
|
.name { |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 500; |
||||
|
line-height: 40rpx; |
||||
|
color: #000000; |
||||
|
|
||||
|
.status { |
||||
|
font-size: 20rpx; |
||||
|
font-weight: normal; |
||||
|
border-radius: 999rpx; |
||||
|
padding: 8rpx 24rpx; |
||||
|
line-height: 20rpx; |
||||
|
color: #2563eb; |
||||
|
background: rgba(37, 99, 235, 0.1); |
||||
|
|
||||
|
&.un { |
||||
|
color: #f44336; |
||||
|
background: rgba(244, 67, 54, 0.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.votes { |
||||
|
font-size: 28rpx; |
||||
|
line-height: 40rpx; |
||||
|
color: #6b7280; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.progress { |
||||
|
width: 192rpx; |
||||
|
height: min-content; |
||||
|
|
||||
|
&-text { |
||||
|
padding-top: 8rpx; |
||||
|
color: #6b7280; |
||||
|
font-size: 24rpx; |
||||
|
line-height: 32rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&-bts { |
||||
|
padding: 16rpx; |
||||
|
margin: 48rpx 0 24rpx; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: normal; |
||||
|
line-height: 42rpx; |
||||
|
text-align: center; |
||||
|
color: #ffffff; |
||||
|
background-color: #2563eb; |
||||
|
border-radius: 8rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,331 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import useUserStore from '@/store/user' |
||||
|
import { list as listApi, type dateListtype, update as updateApi, getMember_mobile} from '@/api/user' |
||||
|
import { getAdminPhone } from '@/api/login' |
||||
|
|
||||
|
const userStore = useUserStore() |
||||
|
|
||||
|
const isHandleUserInfo = computed(() => Object.keys(userStore.userInfo).length === 0) |
||||
|
|
||||
|
const keyword = ref('') |
||||
|
|
||||
|
const list = ref<dateListtype[]>([]) |
||||
|
|
||||
|
const activeKey = ref(0) |
||||
|
|
||||
|
const amdinPhone = ref('') |
||||
|
|
||||
|
const navto = (url: string, params = {}) => uni.$util.goToPage({ url, params }) |
||||
|
|
||||
|
|
||||
|
|
||||
|
const getList = uni.$util.throttle(() => { |
||||
|
if (keyword.value === '') { |
||||
|
uni.showToast({ title: '请输入姓名', icon: 'none' }) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// uni.showLoading({ mask: true, title: '加载中...' }) |
||||
|
|
||||
|
listApi({ name: keyword.value, meetId: userStore.meetId }) |
||||
|
.then((res) => { |
||||
|
const { data } = res as { data: dateListtype[] } |
||||
|
list.value = data || [] |
||||
|
// uni.hideLoading() |
||||
|
}) |
||||
|
.catch(() => uni.hideLoading()) |
||||
|
}) |
||||
|
|
||||
|
const updateUserInfo = () => { |
||||
|
userStore.bindUser(list.value[activeKey.value].id as number).then(() => { |
||||
|
reset() |
||||
|
uni.showToast({ title: '提交成功,等待投票!', icon: 'none' }) |
||||
|
userStore.getUserInfo() |
||||
|
|
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const reset = () => { |
||||
|
activeKey.value = 0 |
||||
|
keyword.value = '' |
||||
|
list.value = [] |
||||
|
} |
||||
|
|
||||
|
const showEdit = ref(false) |
||||
|
|
||||
|
const popFrom = reactive({ |
||||
|
label: '', |
||||
|
key: '', |
||||
|
value: '' |
||||
|
}) |
||||
|
const openPopup = (key: string, label: string) => { |
||||
|
popFrom.label = label |
||||
|
popFrom.key = key |
||||
|
popFrom.value = userStore.userInfo[key] |
||||
|
showEdit.value = true |
||||
|
} |
||||
|
|
||||
|
const save = () => { |
||||
|
if (popFrom.value === '') { |
||||
|
uni.showToast({ title: `请输入${popFrom.label}`, icon: 'none' }) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
uni.showLoading({ mask: true, title: '保存中...' }) |
||||
|
|
||||
|
updateApi({ [popFrom.key]: popFrom.value }, userStore.openId).then(() => { |
||||
|
uni.hideLoading() |
||||
|
userStore.userInfo[popFrom.key] = popFrom.value |
||||
|
showEdit.value = false |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
onShow(() => { |
||||
|
reset() |
||||
|
getAdminPhone().then((res) => { |
||||
|
const { data } = res as { data: string } |
||||
|
amdinPhone.value = data || '' |
||||
|
|
||||
|
}) |
||||
|
}) |
||||
|
|
||||
|
onPullDownRefresh(() => userStore.getUserInfo()) |
||||
|
</script> |
||||
|
<template> |
||||
|
<view class="userview"> |
||||
|
<!-- 搜索信息 --> |
||||
|
<block v-if="isHandleUserInfo"> |
||||
|
<view class="userview-search box flex"> |
||||
|
<view class="userview-search-label">姓名</view> |
||||
|
<input class="flex1" type="text" placeholder="请输入您的姓名" v-model="keyword" placeholder-class="placeholder" /> |
||||
|
<view class="userview-search-bts" @click.stop="getList">搜索</view> |
||||
|
</view> |
||||
|
|
||||
|
<block v-if="list.length > 0"> |
||||
|
<view |
||||
|
class="userview-info box" |
||||
|
:class="{ active: activeKey === index }" |
||||
|
v-for="(row, index) in list" |
||||
|
:key="index" |
||||
|
@click="activeKey = index" |
||||
|
> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">姓名</view> |
||||
|
<view class="userview-info-item-content flex">{{ row.name }}</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">电话</view> |
||||
|
<view class="userview-info-item-content flex">{{ row.mobile }}</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">工作单位</view> |
||||
|
<view class="userview-info-item-content flex">{{ row.work_unit }}</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</block> |
||||
|
<ex-empty v-show="list.length <= 0" /> |
||||
|
<view class="flex-center-evenly"> |
||||
|
<view class="bts plain" v-if="list.length > 0" @click.stop="updateUserInfo">确认信息</view> |
||||
|
<view class="bts" @click="navto('pages/mine/add')">新建信息</view> |
||||
|
</view> |
||||
|
</block> |
||||
|
|
||||
|
<!-- 详细信息 --> |
||||
|
<block v-else> |
||||
|
<view class="userview-info box"> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">姓名</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.name }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">电话</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.mobile }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">性别</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.sex === 1 ? '男' : '女' }}</text> |
||||
|
<u-icon @click.stop="openPopup('sex', '性别')" name="edit-pen-fill" color="#2563EB" size="38rpx" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">民族</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.nation }}</text> |
||||
|
<u-icon @click.stop="openPopup('nation', '民族')" name="edit-pen-fill" color="#2563EB" size="38rpx" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">年龄</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.age }}</text> |
||||
|
<u-icon @click.stop="openPopup('age', '年龄')" name="edit-pen-fill" color="#2563EB" size="38rpx" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">工作单位</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.work_unit }}</text> |
||||
|
<u-icon @click.stop="openPopup('work_unit', '工作单位')" name="edit-pen-fill" color="#2563EB" size="38rpx" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex-center-between userview-info-item"> |
||||
|
<view class="userview-info-item-label">职位</view> |
||||
|
<view class="userview-info-item-content flex"> |
||||
|
<text>{{ userStore.userInfo.position }}</text> |
||||
|
<u-icon @click.stop="openPopup('position', '职位')" name="edit-pen-fill" color="#2563EB" size="38rpx" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="userview-info box admin"> |
||||
|
<view>* 姓名和电话信息需要管理员修改</view> |
||||
|
<view> |
||||
|
<text>管理员电话:</text> |
||||
|
<text class="phone">{{ amdinPhone }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</block> |
||||
|
|
||||
|
<u-popup :show="showEdit" mode="center" @close="showEdit = false" :round="10"> |
||||
|
<view class="popupView"> |
||||
|
<view class="title">修改{{ popFrom.label }}</view> |
||||
|
<view v-if="popFrom.key === 'sex'" class="flex-center-between sexview"> |
||||
|
<text>性别</text> |
||||
|
<u-radio-group v-model="popFrom.value" placement="row"> |
||||
|
<u-radio shape="circle" label="男" :name="1" /> |
||||
|
<u-radio shape="circle" label="女" :name="2" /> |
||||
|
</u-radio-group> |
||||
|
</view> |
||||
|
<u-input v-else :placeholder="`请输入${popFrom.label}`" input-align="right" v-model="popFrom.value"> |
||||
|
<template v-slot:prefix> |
||||
|
<text style="color: #909399">{{ popFrom.label }}</text> |
||||
|
</template> |
||||
|
</u-input> |
||||
|
|
||||
|
<view class="bts" @click="save">确认信息</view> |
||||
|
</view> |
||||
|
</u-popup> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.userview { |
||||
|
width: 100%; |
||||
|
padding: 32rpx; |
||||
|
min-height: 100vh; |
||||
|
box-sizing: border-box; |
||||
|
background-color: #f9fafb; |
||||
|
|
||||
|
.popupView { |
||||
|
width: 90vw; |
||||
|
padding: 20rpx 40rpx; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 36rpx; |
||||
|
font-weight: 500; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
:deep(.u-input) { |
||||
|
border-width: 2rpx !important; |
||||
|
} |
||||
|
|
||||
|
.bts { |
||||
|
margin-top: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.sexview { |
||||
|
:deep(.u-radio-group) { |
||||
|
justify-content: flex-end !important; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.box { |
||||
|
margin-bottom: 32rpx; |
||||
|
border-radius: 24rpx; |
||||
|
background-color: #ffffff; |
||||
|
box-shadow: 0 2rpx 4rpx 0 rgba(0, 0, 0, 0.05); |
||||
|
} |
||||
|
|
||||
|
&-search { |
||||
|
color: #4b5563; |
||||
|
font-size: 24rpx; |
||||
|
line-height: 40rpx; |
||||
|
padding: 46rpx 32rpx; |
||||
|
|
||||
|
&-label { |
||||
|
margin-right: 44rpx; |
||||
|
} |
||||
|
|
||||
|
&-bts { |
||||
|
color: #2563eb; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&-info { |
||||
|
font-size: 28rpx; |
||||
|
font-weight: normal; |
||||
|
line-height: 40rpx; |
||||
|
padding: 0 32rpx 32rpx; |
||||
|
border: 1rpx solid #fff; |
||||
|
|
||||
|
&.active { |
||||
|
border-color: #2563eb; |
||||
|
} |
||||
|
|
||||
|
&.admin { |
||||
|
padding: 32rpx; |
||||
|
color: #6b7280; |
||||
|
margin: 0 0 60rpx; |
||||
|
|
||||
|
.phone { |
||||
|
color: #2563eb; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&-item { |
||||
|
padding: 60rpx 0 24rpx; |
||||
|
border-top: 1rpx solid #e5e7eb; |
||||
|
|
||||
|
&:first-child { |
||||
|
border: none; |
||||
|
} |
||||
|
|
||||
|
&-label { |
||||
|
color: #4b5563; |
||||
|
} |
||||
|
|
||||
|
&-content { |
||||
|
color: #1f2937; |
||||
|
|
||||
|
> text { |
||||
|
margin-right: 16rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bts { |
||||
|
color: #fff; |
||||
|
font-size: 28rpx; |
||||
|
line-height: 40rpx; |
||||
|
text-align: center; |
||||
|
border-radius: 8rpx; |
||||
|
padding: 24rpx 80rpx; |
||||
|
letter-spacing: 4rpx; |
||||
|
border: 1rpx solid #2563eb; |
||||
|
background-color: #2563eb; |
||||
|
|
||||
|
&.plain { |
||||
|
color: #2563eb; |
||||
|
background-color: #eff6ff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,51 @@ |
|||||
|
// import { getAuthorization } from '@/config'
|
||||
|
|
||||
|
// 白名单
|
||||
|
// const whiteList = ['/agentpages/index/index', '/agentpages/mine/index']
|
||||
|
|
||||
|
export default async function () { |
||||
|
const list = ['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'] |
||||
|
|
||||
|
// 用遍历的方式分别为,uni.navigateTo,uni.redirectTo,uni.reLaunch,uni.switchTab这4个路由方法添加拦截器
|
||||
|
list.forEach((item) => { |
||||
|
uni.addInterceptor(item, { |
||||
|
invoke(e) { |
||||
|
console.log('e', e) |
||||
|
|
||||
|
// 获取要跳转的页面路径(url去掉"?"和"?"后的参数)
|
||||
|
// const url = e.url.split('?')[0]
|
||||
|
// const type = url.split('/')[1] || ''
|
||||
|
|
||||
|
// let data
|
||||
|
// if (getAuthorization()) {
|
||||
|
// data = JSON.parse(getAuthorization())
|
||||
|
// } else {
|
||||
|
// data = { userInfo: { is_real: 0 } }
|
||||
|
// }
|
||||
|
|
||||
|
// // 判断当前窗口是白名单,如果是则不重定向路由
|
||||
|
// if (type === 'agentpages' && !whiteList.includes(url) && !data.userInfo.is_real) {
|
||||
|
// uni.showModal({
|
||||
|
// title: '提示',
|
||||
|
// content: '请先实名认证',
|
||||
|
// showCancel: true,
|
||||
|
// success({ confirm }) {
|
||||
|
// if (confirm) {
|
||||
|
// uni.navigateTo({
|
||||
|
// url: '/pages/mine/authentication'
|
||||
|
// })
|
||||
|
// }
|
||||
|
// }
|
||||
|
// })
|
||||
|
// return false
|
||||
|
// }
|
||||
|
|
||||
|
return e |
||||
|
}, |
||||
|
fail(err) { |
||||
|
// 失败回调拦截
|
||||
|
console.log(err) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,257 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { shareApi } from '@/api/agent/promotion' |
||||
|
import { getHeaderImage } from '@/utils/common' |
||||
|
|
||||
|
const { screenWidth } = uni.getSystemInfoSync() |
||||
|
|
||||
|
const qrcodeRef = ref() |
||||
|
|
||||
|
const userInfo = ref<{ head_img: string; id: number; phone: string; nickname: string }>({ |
||||
|
head_img: '', |
||||
|
id: 0, |
||||
|
phone: '', |
||||
|
nickname: '' |
||||
|
}) |
||||
|
|
||||
|
const showSaveImgWin = ref(false) |
||||
|
|
||||
|
const canvasToTempFilePath = ref('') |
||||
|
|
||||
|
const oncomplete = ({ success }: { success: boolean }) => { |
||||
|
if (!success) return |
||||
|
qrcodeRef.value.toTempFilePath({ |
||||
|
success: ({ tempFilePath }: { tempFilePath: string }) => { |
||||
|
createCanvas(tempFilePath) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const saveShareImg = () => { |
||||
|
uni.saveImageToPhotosAlbum({ |
||||
|
filePath: canvasToTempFilePath.value, |
||||
|
success: () => { |
||||
|
showSaveImgWin.value = false |
||||
|
uni.showToast({ |
||||
|
title: '保存成功,快去分享到朋友圈吧~', |
||||
|
icon: 'none', |
||||
|
duration: 1000 |
||||
|
}) |
||||
|
}, |
||||
|
fail: () => { |
||||
|
uni.showToast({ |
||||
|
title: '保存失败,请检查是否授权保存图片权限~', |
||||
|
icon: 'none', |
||||
|
duration: 1000 |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const createCanvas = (tempFilePath: string) => { |
||||
|
uni.getImageInfo({ |
||||
|
src: getHeaderImage(userInfo.value.head_img), |
||||
|
success: ({ path }) => { |
||||
|
const ctx = uni.createCanvasContext('shareCanvas', this) |
||||
|
const canvasWidth = screenWidth - 30 |
||||
|
const canvasHeight = (screenWidth - 30) * 1.62 |
||||
|
|
||||
|
ctx.translate(0, 0) |
||||
|
ctx.beginPath() |
||||
|
ctx.drawImage('../../static/invite.jpg', 0, 0, canvasWidth, canvasHeight) |
||||
|
ctx.restore() |
||||
|
|
||||
|
ctx.beginPath() |
||||
|
ctx.translate(0, canvasHeight - 78) |
||||
|
ctx.beginPath() |
||||
|
ctx.setFillStyle('rgba(0, 0, 0, 0.24)') |
||||
|
ctx.fillRect(0, 0, canvasWidth, 78) |
||||
|
ctx.save() |
||||
|
|
||||
|
ctx.save() |
||||
|
ctx.beginPath() |
||||
|
ctx.arc(40, 40, 22, 0, 2 * Math.PI, false) |
||||
|
ctx.setFillStyle('rgba(0, 0, 0, 0.29)') |
||||
|
ctx.clip() |
||||
|
ctx.drawImage(path, 19, 19, 42, 42) |
||||
|
ctx.restore() |
||||
|
|
||||
|
ctx.font = 'normal normal 13px sans-serif' |
||||
|
ctx.setFillStyle('#ffffff') |
||||
|
ctx.fillText('用户昵称', 71, 37) |
||||
|
|
||||
|
ctx.font = 'normal normal 12px sans-serif' |
||||
|
ctx.setFillStyle('#ffffff') |
||||
|
ctx.fillText(`${userInfo.value.nickname}`, 71, 54) |
||||
|
ctx.save() |
||||
|
|
||||
|
ctx.beginPath() |
||||
|
const x = canvasWidth - 78, |
||||
|
y = 7, |
||||
|
width = 64, |
||||
|
height = 64, |
||||
|
radius = 4 |
||||
|
ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5) |
||||
|
ctx.lineTo(x + width - radius, y) |
||||
|
ctx.arc(x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2) |
||||
|
ctx.lineTo(x + width, y + height - radius) |
||||
|
ctx.arc(x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5) |
||||
|
ctx.lineTo(x + radius, y + height) |
||||
|
ctx.arc(x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI) |
||||
|
ctx.lineTo(x, y + radius) |
||||
|
ctx.setFillStyle('#ffffff') |
||||
|
ctx.fill() |
||||
|
ctx.closePath() |
||||
|
|
||||
|
ctx.beginPath() |
||||
|
ctx.drawImage(tempFilePath, x + 3, y + 3, 58, 58) |
||||
|
ctx.restore() |
||||
|
|
||||
|
ctx.draw(false, () => { |
||||
|
uni.canvasToTempFilePath({ |
||||
|
width: canvasWidth, |
||||
|
height: canvasHeight, |
||||
|
destWidth: canvasWidth * 2, |
||||
|
destHeight: canvasHeight * 2, |
||||
|
canvasId: 'shareCanvas', |
||||
|
quality: 1, |
||||
|
success: ({ tempFilePath }) => { |
||||
|
canvasToTempFilePath.value = tempFilePath |
||||
|
}, |
||||
|
complete: () => { |
||||
|
uni.hideLoading() |
||||
|
setTimeout(() => uni.hideToast(), 1000) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// const shareToFriends = () => { |
||||
|
// plus.share.sendWithSystem( |
||||
|
// { content: '分享内容', href: 'https://www.dcloud.io/' }, |
||||
|
// function () { |
||||
|
// console.log('分享成功') |
||||
|
// }, |
||||
|
// function (e) { |
||||
|
// console.log('分享失败:' + JSON.stringify(e)) |
||||
|
// } |
||||
|
// ) |
||||
|
// } |
||||
|
|
||||
|
onLoad(() => { |
||||
|
uni.showLoading({ title: '加载中...' }) |
||||
|
shareApi().then((res) => { |
||||
|
const { data } = res as { data: { head_img: string; id: number; phone: string; nickname: string } } |
||||
|
userInfo.value = data |
||||
|
qrcodeRef.value.make() |
||||
|
}) |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<view class="invite"> |
||||
|
<ex-header title="邀请好友" /> |
||||
|
|
||||
|
<uv-qrcode |
||||
|
ref="qrcodeRef" |
||||
|
class="qrcode" |
||||
|
size="174rpx" |
||||
|
:value="`http://pos-admin.lingji.vip/#/sign?p=${userInfo.phone}&t=a`" |
||||
|
@complete="oncomplete" |
||||
|
/> |
||||
|
|
||||
|
<canvas canvas-id="shareCanvas" :style="{ width: `${screenWidth - 30}px`, height: `${(screenWidth - 30) * 1.62}px` }" hidpi /> |
||||
|
<image @longpress="showSaveImgWin = true" style="width: 100%; height: 100%" :src="canvasToTempFilePath" /> |
||||
|
|
||||
|
<view class="option-box flex-center-between"> |
||||
|
<view class="btn" @click="showSaveImgWin = true">保存图片</view> |
||||
|
|
||||
|
<!-- <view class="option-box-item"> |
||||
|
<view class="img-box"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/share/circle_of_friends.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="label">朋友圈</view> |
||||
|
</view> |
||||
|
<view class="option-box-item" @click="shareToFriends()"> |
||||
|
<view class="img-box"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/share/wechart.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="label">微信</view> |
||||
|
</view> |
||||
|
<view class="option-box-item" @click="downloadFn()"> |
||||
|
<view class="img-box"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/share/download.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="label">保存</view> |
||||
|
</view> --> |
||||
|
</view> |
||||
|
|
||||
|
<u-modal |
||||
|
:show="showSaveImgWin" |
||||
|
show-cancel-button |
||||
|
close-on-click-overlay |
||||
|
@cancel="showSaveImgWin = false" |
||||
|
@close="showSaveImgWin = false" |
||||
|
@confirm="saveShareImg" |
||||
|
> |
||||
|
确定要保存图片吗? |
||||
|
</u-modal> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.invite { |
||||
|
width: 100vw; |
||||
|
min-height: 100vh; |
||||
|
padding: 30rpx; |
||||
|
|
||||
|
.qrcode { |
||||
|
position: absolute; |
||||
|
top: -100%; |
||||
|
} |
||||
|
|
||||
|
.option-box { |
||||
|
padding: 46rpx 37rpx 102rpx; |
||||
|
|
||||
|
&-item { |
||||
|
.img-box { |
||||
|
@extend .flex; |
||||
|
width: 104rpx; |
||||
|
height: 104rpx; |
||||
|
overflow: hidden; |
||||
|
border-radius: 50%; |
||||
|
margin-bottom: 10rpx; |
||||
|
background-color: #f2f6ff; |
||||
|
|
||||
|
image { |
||||
|
width: 66rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.label { |
||||
|
width: 100%; |
||||
|
color: #000; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 400; |
||||
|
letter-spacing: 0; |
||||
|
line-height: 40rpx; |
||||
|
text-align: center; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
width: 100%; |
||||
|
color: #ffffff; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 500; |
||||
|
letter-spacing: 0; |
||||
|
line-height: 40rpx; |
||||
|
text-align: center; |
||||
|
padding: 20rpx 0; |
||||
|
border-radius: 8rpx; |
||||
|
background: linear-gradient(90deg, #4778ff 0%, #4778ffb8 100%); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 923 B |
|
After Width: | Height: | Size: 750 B |
|
After Width: | Height: | Size: 918 B |
|
After Width: | Height: | Size: 1005 B |
@ -0,0 +1,10 @@ |
|||||
|
import { createPinia } from 'pinia' |
||||
|
import { createUnistorage } from 'pinia-plugin-unistorage' |
||||
|
|
||||
|
const store = createPinia() |
||||
|
// 使用该插件
|
||||
|
// 关键代码 👇
|
||||
|
store.use(createUnistorage()) |
||||
|
|
||||
|
//导出
|
||||
|
export default store |
||||
@ -0,0 +1,115 @@ |
|||||
|
// 定义组合式API仓库
|
||||
|
import { defineStore } from 'pinia' |
||||
|
import { getPrefixName } from '@/config' |
||||
|
import { getOpenid } from '@/api/login' |
||||
|
import { infoForOpenid, bind as bindApi } from '@/api/user' |
||||
|
|
||||
|
interface userInfoStoreInt { |
||||
|
[n: string]: any |
||||
|
} |
||||
|
export default defineStore( |
||||
|
getPrefixName('user'), |
||||
|
() => { |
||||
|
const openId = ref('') |
||||
|
const mobile = ref('') |
||||
|
const meetId = ref('') |
||||
|
const showtoast = ref(false) |
||||
|
const userInfo = ref<userInfoStoreInt>({}) |
||||
|
|
||||
|
function getopenid(params: { code: string }) { |
||||
|
return new Promise<any>((resolve, reject) => { |
||||
|
getOpenid(params) |
||||
|
.then((res) => { |
||||
|
const { data } = res as { data: string } |
||||
|
|
||||
|
openId.value = data |
||||
|
|
||||
|
resolve({ code: 1, message: '登录成功~' }) |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
reject(err) |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function getUserInfo() { |
||||
|
return new Promise<any>( (resolve, reject) => { |
||||
|
infoForOpenid({ openid: openId.value, mobile: mobile.value, meetId: meetId.value}) |
||||
|
.then((res) => { |
||||
|
const { data } = res as { data: userInfoStoreInt } |
||||
|
userInfo.value = data || {} |
||||
|
resolve({ code: 1, data, message: 'SUCCESS' }) |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
reject(err) |
||||
|
}) |
||||
|
|
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function bindUser(id: number) { |
||||
|
return new Promise<any>((resolve, reject) => { |
||||
|
bindApi({ id, openid: openId.value }) |
||||
|
.then(() => { |
||||
|
resolve({ code: 1, message: 'SUCCESS' }) |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
reject(err) |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
function logOut() { |
||||
|
userInfo.value = {} |
||||
|
uni.clearStorageSync() |
||||
|
|
||||
|
uni.showToast({ |
||||
|
icon: 'none', |
||||
|
title: '退出成功', |
||||
|
mask: true, |
||||
|
success() { |
||||
|
setTimeout(() => uni.reLaunch({ url: 'pages/login/login' }), 1000) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
openId, |
||||
|
mobile, |
||||
|
meetId, |
||||
|
showtoast, |
||||
|
userInfo, |
||||
|
getopenid, |
||||
|
bindUser, |
||||
|
getUserInfo, |
||||
|
logOut |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
unistorage: { |
||||
|
serializer: { |
||||
|
// 序列化,默认为 JSON.stringify
|
||||
|
serialize(v) { |
||||
|
return JSON.stringify(v) |
||||
|
}, |
||||
|
// 反序列化,默认为 JSON.parse
|
||||
|
deserialize(v) { |
||||
|
return JSON.parse(v) |
||||
|
} |
||||
|
} |
||||
|
} // 开启后对 state 的数据读写都将持久化
|
||||
|
// unistorage: {
|
||||
|
// key: 'userInfo', // 缓存的键,默认为该 store 的 id,这里是 main,
|
||||
|
// paths: ['userInfo.token'], // 需要缓存的路径,这里设置 foo 和 nested 下的 data 会被缓存
|
||||
|
// // 初始化恢复前触发
|
||||
|
// beforeRestore(ctx: any) {
|
||||
|
// console.log(ctx)
|
||||
|
// },
|
||||
|
// // 初始化恢复后触发
|
||||
|
// afterRestore(ctx: any) {
|
||||
|
// console.log('ctx', ctx)
|
||||
|
// },
|
||||
|
|
||||
|
// },
|
||||
|
} |
||||
|
) |
||||
@ -0,0 +1,180 @@ |
|||||
|
/* eslint-disable */ |
||||
|
/* prettier-ignore */ |
||||
|
// @ts-nocheck
|
||||
|
// noinspection JSUnusedGlobalSymbols
|
||||
|
// Generated by unplugin-auto-import
|
||||
|
export {} |
||||
|
declare global { |
||||
|
const EffectScope: typeof import('vue')['EffectScope'] |
||||
|
const computed: typeof import('vue')['computed'] |
||||
|
const createApp: typeof import('vue')['createApp'] |
||||
|
const customRef: typeof import('vue')['customRef'] |
||||
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] |
||||
|
const defineComponent: typeof import('vue')['defineComponent'] |
||||
|
const effectScope: typeof import('vue')['effectScope'] |
||||
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance'] |
||||
|
const getCurrentScope: typeof import('vue')['getCurrentScope'] |
||||
|
const h: typeof import('vue')['h'] |
||||
|
const inject: typeof import('vue')['inject'] |
||||
|
const isProxy: typeof import('vue')['isProxy'] |
||||
|
const isReactive: typeof import('vue')['isReactive'] |
||||
|
const isReadonly: typeof import('vue')['isReadonly'] |
||||
|
const isRef: typeof import('vue')['isRef'] |
||||
|
const markRaw: typeof import('vue')['markRaw'] |
||||
|
const nextTick: typeof import('vue')['nextTick'] |
||||
|
const onActivated: typeof import('vue')['onActivated'] |
||||
|
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites'] |
||||
|
const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress'] |
||||
|
const onBeforeMount: typeof import('vue')['onBeforeMount'] |
||||
|
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] |
||||
|
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] |
||||
|
const onDeactivated: typeof import('vue')['onDeactivated'] |
||||
|
const onError: typeof import('@dcloudio/uni-app')['onError'] |
||||
|
const onErrorCaptured: typeof import('vue')['onErrorCaptured'] |
||||
|
const onHide: typeof import('@dcloudio/uni-app')['onHide'] |
||||
|
const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch'] |
||||
|
const onLoad: typeof import('@dcloudio/uni-app')['onLoad'] |
||||
|
const onMounted: typeof import('vue')['onMounted'] |
||||
|
const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap'] |
||||
|
const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged'] |
||||
|
const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked'] |
||||
|
const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed'] |
||||
|
const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged'] |
||||
|
const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound'] |
||||
|
const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll'] |
||||
|
const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh'] |
||||
|
const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom'] |
||||
|
const onReady: typeof import('@dcloudio/uni-app')['onReady'] |
||||
|
const onRenderTracked: typeof import('vue')['onRenderTracked'] |
||||
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered'] |
||||
|
const onResize: typeof import('@dcloudio/uni-app')['onResize'] |
||||
|
const onScopeDispose: typeof import('vue')['onScopeDispose'] |
||||
|
const onServerPrefetch: typeof import('vue')['onServerPrefetch'] |
||||
|
const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage'] |
||||
|
const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline'] |
||||
|
const onShow: typeof import('@dcloudio/uni-app')['onShow'] |
||||
|
const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap'] |
||||
|
const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange'] |
||||
|
const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection'] |
||||
|
const onUnload: typeof import('@dcloudio/uni-app')['onUnload'] |
||||
|
const onUnmounted: typeof import('vue')['onUnmounted'] |
||||
|
const onUpdated: typeof import('vue')['onUpdated'] |
||||
|
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] |
||||
|
const provide: typeof import('vue')['provide'] |
||||
|
const reactive: typeof import('vue')['reactive'] |
||||
|
const readonly: typeof import('vue')['readonly'] |
||||
|
const ref: typeof import('vue')['ref'] |
||||
|
const resolveComponent: typeof import('vue')['resolveComponent'] |
||||
|
const shallowReactive: typeof import('vue')['shallowReactive'] |
||||
|
const shallowReadonly: typeof import('vue')['shallowReadonly'] |
||||
|
const shallowRef: typeof import('vue')['shallowRef'] |
||||
|
const toRaw: typeof import('vue')['toRaw'] |
||||
|
const toRef: typeof import('vue')['toRef'] |
||||
|
const toRefs: typeof import('vue')['toRefs'] |
||||
|
const toValue: typeof import('vue')['toValue'] |
||||
|
const triggerRef: typeof import('vue')['triggerRef'] |
||||
|
const unref: typeof import('vue')['unref'] |
||||
|
const useAttrs: typeof import('vue')['useAttrs'] |
||||
|
const useCssModule: typeof import('vue')['useCssModule'] |
||||
|
const useCssVars: typeof import('vue')['useCssVars'] |
||||
|
const useId: typeof import('vue')['useId'] |
||||
|
const useModel: typeof import('vue')['useModel'] |
||||
|
const useSlots: typeof import('vue')['useSlots'] |
||||
|
const useTemplateRef: typeof import('vue')['useTemplateRef'] |
||||
|
const watch: typeof import('vue')['watch'] |
||||
|
const watchEffect: typeof import('vue')['watchEffect'] |
||||
|
const watchPostEffect: typeof import('vue')['watchPostEffect'] |
||||
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect'] |
||||
|
} |
||||
|
// for type re-export
|
||||
|
declare global { |
||||
|
// @ts-ignore
|
||||
|
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' |
||||
|
import('vue') |
||||
|
} |
||||
|
// for vue template auto import
|
||||
|
import { UnwrapRef } from 'vue' |
||||
|
declare module 'vue' { |
||||
|
interface ComponentCustomProperties { |
||||
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> |
||||
|
readonly computed: UnwrapRef<typeof import('vue')['computed']> |
||||
|
readonly createApp: UnwrapRef<typeof import('vue')['createApp']> |
||||
|
readonly customRef: UnwrapRef<typeof import('vue')['customRef']> |
||||
|
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']> |
||||
|
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']> |
||||
|
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']> |
||||
|
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']> |
||||
|
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']> |
||||
|
readonly h: UnwrapRef<typeof import('vue')['h']> |
||||
|
readonly inject: UnwrapRef<typeof import('vue')['inject']> |
||||
|
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> |
||||
|
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> |
||||
|
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> |
||||
|
readonly isRef: UnwrapRef<typeof import('vue')['isRef']> |
||||
|
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> |
||||
|
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> |
||||
|
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']> |
||||
|
readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']> |
||||
|
readonly onBackPress: UnwrapRef<typeof import('@dcloudio/uni-app')['onBackPress']> |
||||
|
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']> |
||||
|
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']> |
||||
|
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']> |
||||
|
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']> |
||||
|
readonly onError: UnwrapRef<typeof import('@dcloudio/uni-app')['onError']> |
||||
|
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']> |
||||
|
readonly onHide: UnwrapRef<typeof import('@dcloudio/uni-app')['onHide']> |
||||
|
readonly onLaunch: UnwrapRef<typeof import('@dcloudio/uni-app')['onLaunch']> |
||||
|
readonly onLoad: UnwrapRef<typeof import('@dcloudio/uni-app')['onLoad']> |
||||
|
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']> |
||||
|
readonly onNavigationBarButtonTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']> |
||||
|
readonly onNavigationBarSearchInputChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']> |
||||
|
readonly onNavigationBarSearchInputClicked: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']> |
||||
|
readonly onNavigationBarSearchInputConfirmed: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']> |
||||
|
readonly onNavigationBarSearchInputFocusChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']> |
||||
|
readonly onPageNotFound: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageNotFound']> |
||||
|
readonly onPageScroll: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageScroll']> |
||||
|
readonly onPullDownRefresh: UnwrapRef<typeof import('@dcloudio/uni-app')['onPullDownRefresh']> |
||||
|
readonly onReachBottom: UnwrapRef<typeof import('@dcloudio/uni-app')['onReachBottom']> |
||||
|
readonly onReady: UnwrapRef<typeof import('@dcloudio/uni-app')['onReady']> |
||||
|
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']> |
||||
|
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']> |
||||
|
readonly onResize: UnwrapRef<typeof import('@dcloudio/uni-app')['onResize']> |
||||
|
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']> |
||||
|
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']> |
||||
|
readonly onShareAppMessage: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareAppMessage']> |
||||
|
readonly onShareTimeline: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareTimeline']> |
||||
|
readonly onShow: UnwrapRef<typeof import('@dcloudio/uni-app')['onShow']> |
||||
|
readonly onTabItemTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onTabItemTap']> |
||||
|
readonly onThemeChange: UnwrapRef<typeof import('@dcloudio/uni-app')['onThemeChange']> |
||||
|
readonly onUnhandledRejection: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnhandledRejection']> |
||||
|
readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']> |
||||
|
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']> |
||||
|
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> |
||||
|
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']> |
||||
|
readonly provide: UnwrapRef<typeof import('vue')['provide']> |
||||
|
readonly reactive: UnwrapRef<typeof import('vue')['reactive']> |
||||
|
readonly readonly: UnwrapRef<typeof import('vue')['readonly']> |
||||
|
readonly ref: UnwrapRef<typeof import('vue')['ref']> |
||||
|
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']> |
||||
|
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']> |
||||
|
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']> |
||||
|
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']> |
||||
|
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> |
||||
|
readonly toRef: UnwrapRef<typeof import('vue')['toRef']> |
||||
|
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> |
||||
|
readonly toValue: UnwrapRef<typeof import('vue')['toValue']> |
||||
|
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> |
||||
|
readonly unref: UnwrapRef<typeof import('vue')['unref']> |
||||
|
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> |
||||
|
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']> |
||||
|
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']> |
||||
|
readonly useId: UnwrapRef<typeof import('vue')['useId']> |
||||
|
readonly useModel: UnwrapRef<typeof import('vue')['useModel']> |
||||
|
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> |
||||
|
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']> |
||||
|
readonly watch: UnwrapRef<typeof import('vue')['watch']> |
||||
|
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> |
||||
|
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> |
||||
|
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']> |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
/// <reference types="vite/client" />
|
||||
|
/// <reference types="@dcloudio/types/index" />
|
||||
|
/// <reference types="uview-plus/types/index" />
|
||||
|
/// <reference types="feng-uniapp-exploit/types/index" />
|
||||
|
|
||||
|
declare module '*.vue' { |
||||
|
import { DefineComponent } from 'vue' |
||||
|
const component: DefineComponent<{}, {}, any> |
||||
|
export default component |
||||
|
} |
||||
|
|
||||
|
declare module 'uview-plus' |
||||
|
declare module 'feng-uniapp-exploit' |
||||
@ -0,0 +1,29 @@ |
|||||
|
/* eslint-disable prettier/prettier */ |
||||
|
|
||||
|
declare global { |
||||
|
type useType = 'client' | 'agent' |
||||
|
|
||||
|
/** |
||||
|
* 公共的路径 |
||||
|
* @author shenname <shenname@163.com> |
||||
|
* @license MIT |
||||
|
* @param { string } fileName 文件名称 |
||||
|
* @param { string } filePath 文件路径 |
||||
|
* @example |
||||
|
* fileName: images.png |
||||
|
* filePath: images |
||||
|
*/ |
||||
|
interface imgUrlInt { |
||||
|
fileName: string |
||||
|
filePath?: string |
||||
|
} |
||||
|
|
||||
|
interface pageType { |
||||
|
page: number |
||||
|
limit: number |
||||
|
total?: number |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
export { } |
||||
@ -0,0 +1,118 @@ |
|||||
|
@import 'uview-plus/theme.scss'; |
||||
|
|
||||
|
#app { |
||||
|
box-sizing: border-box; |
||||
|
background-color: #f5f5f5 |
||||
|
} |
||||
|
|
||||
|
/* 颜色变量 */ |
||||
|
|
||||
|
/*============================= 文字尺寸 =============================*/ |
||||
|
$font-size-20: 20rpx; |
||||
|
$font-size-22: 22rpx; |
||||
|
$font-size-24: 24rpx; |
||||
|
$font-size-26: 26rpx; |
||||
|
$font-size-28: 28rpx; |
||||
|
$font-size-30: 30rpx; |
||||
|
$font-size-32: 32rpx; |
||||
|
$font-size-34: 34rpx; |
||||
|
$font-size-36: 36rpx; |
||||
|
$font-size-40: 40rpx; |
||||
|
|
||||
|
image { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
view { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
/*============================= 弹性盒子 =============================*/ |
||||
|
%flex-base { |
||||
|
display: flex; |
||||
|
flex-wrap: nowrap; |
||||
|
} |
||||
|
|
||||
|
$flex-way: ( |
||||
|
start, |
||||
|
flex-start), |
||||
|
(center, center), |
||||
|
(end, flex-end), |
||||
|
(between, space-between), |
||||
|
(around, space-around), |
||||
|
(evenly, space-evenly |
||||
|
); |
||||
|
|
||||
|
@mixin flex-algin($align) { |
||||
|
@each $way, $justify in $flex-way { |
||||
|
&-#{$way} { |
||||
|
@if $way !=$align { |
||||
|
@if $way !=$align { |
||||
|
@extend %flex-base; |
||||
|
align-items: $align; |
||||
|
justify-content: $justify; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.flex { |
||||
|
@extend %flex-base; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
|
||||
|
@each $way, $justify in (start, flex-start), (center, center), (end, flex-end) { |
||||
|
&-#{$way} { |
||||
|
@include flex-algin($justify); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[class*="flex-"], |
||||
|
[class^="flex"] { |
||||
|
&.nowrap { |
||||
|
flex-wrap: nowrap; |
||||
|
} |
||||
|
|
||||
|
&.stretch { |
||||
|
align-items: stretch; |
||||
|
} |
||||
|
|
||||
|
@each $direction, $name in (row, direction), (column, direction), (wrap, wrap) { |
||||
|
&.#{$direction} { |
||||
|
flex-#{$name}: $direction; |
||||
|
|
||||
|
&-reverse { |
||||
|
flex-#{$name}: '#{$direction}-reverse'; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@for $i from 1 through 4 { |
||||
|
.flex#{$i} { |
||||
|
flex: $i; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/*============================= 文字溢出 =============================*/ |
||||
|
.text-ellipsis { |
||||
|
overflow: hidden; |
||||
|
white-space: nowrap; |
||||
|
text-overflow: ellipsis; |
||||
|
|
||||
|
@for $i from 2 through 4 { |
||||
|
&-#{$i} { |
||||
|
overflow: hidden; |
||||
|
white-space: normal; |
||||
|
text-overflow: ellipsis; |
||||
|
display: -webkit-box; |
||||
|
-webkit-box-orient: vertical; |
||||
|
line-clamp: 1; |
||||
|
-webkit-line-clamp: $i; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
/** |
||||
|
* 获取用户头像地址 |
||||
|
* @author shenname <shenname@163.com> |
||||
|
* @license MIT |
||||
|
* @param { string } url 头像地址 |
||||
|
* @returns { string } |
||||
|
*/ |
||||
|
export const getHeaderImage = (url?: string) => { |
||||
|
if (url) { |
||||
|
return import.meta.env.VITE_APP_BASE_URL + url |
||||
|
} else { |
||||
|
return 'http://cdn-pos.lingji.vip/static/system/headimg.png' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取图片地址 |
||||
|
* @author shenname <shenname@163.com> |
||||
|
* @license MIT |
||||
|
* @param { string } url 图片地址 |
||||
|
* @returns { string } |
||||
|
*/ |
||||
|
export const getImageUrl = (url?: string) => { |
||||
|
return import.meta.env.VITE_APP_BASE_URL + url |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取文件相对路径、URL |
||||
|
* @author shenname <shenname@163.com> |
||||
|
* @license MIT |
||||
|
* @param { string } fileName 文件名称 | 相对路径 |
||||
|
* @param { string } [filePath=images] filePath 文件在 /static 下的路径 获取URL时不传 |
||||
|
* @example |
||||
|
* imgUrl('a.png') |
||||
|
* imgUrl('a.png', '/public/') |
||||
|
* imgUrl('/upload/images/img.png') |
||||
|
* @returns {string} |
||||
|
*/ |
||||
|
export const fileUrl = (fileName: string, filePath: string = 'images'): string => { |
||||
|
if (/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/.test(fileName)) { |
||||
|
return import.meta.env.VITE_APP_BASE_URL + fileName |
||||
|
} else { |
||||
|
return `http://cdn-pos.lingji.vip/static/${filePath}/${fileName}` |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 判断对象是否为空 |
||||
|
* @author shenname <shenname@163.com> |
||||
|
* @license MIT |
||||
|
* @param any |
||||
|
* @returns {boolean} |
||||
|
*/ |
||||
|
export const isEmptyObject = (obj: any): boolean => { |
||||
|
if (obj == null) return true |
||||
|
if (typeof obj !== 'object' || Array.isArray(obj)) return true |
||||
|
return Reflect.ownKeys(obj).length === 0 |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
interface ResponseOptions { |
||||
|
url: string |
||||
|
headers?: { [key: string]: string } |
||||
|
method?: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT' |
||||
|
data?: { [key: string]: any } |
||||
|
isSinglePost?: boolean |
||||
|
} |
||||
|
|
||||
|
export const request = { |
||||
|
isLock: false, |
||||
|
http({ url = '', headers = {}, data = {}, method = 'POST', isSinglePost = false }: ResponseOptions) { |
||||
|
const _this = this |
||||
|
|
||||
|
return new Promise(function (resolve, reject) { |
||||
|
if (isSinglePost && _this.isLock) { |
||||
|
reject({ message: '加载中' }) |
||||
|
} |
||||
|
_this.isLock = true |
||||
|
|
||||
|
// #ifdef APP-PLUS
|
||||
|
url = import.meta.env.VITE_APP_BASE_URL + url |
||||
|
// #endif
|
||||
|
// #ifdef H5
|
||||
|
url = import.meta.env.VITE_APP_BASE_PRE + url |
||||
|
// #endif
|
||||
|
|
||||
|
// #ifdef MP-WEIXIN
|
||||
|
url = import.meta.env.VITE_APP_BASE_URL + url |
||||
|
// #endif
|
||||
|
|
||||
|
const header = Object.assign({ 'content-type': 'application/json', Authorization: '' }, headers) |
||||
|
|
||||
|
uni.request({ |
||||
|
url, |
||||
|
header, |
||||
|
method, |
||||
|
data, |
||||
|
success(res) { |
||||
|
const data = res.data as { code: number; data: object; msg: string } |
||||
|
|
||||
|
switch (data.code) { |
||||
|
case 1: |
||||
|
resolve(res.data) |
||||
|
break |
||||
|
default: |
||||
|
uni.showToast({ title: data.msg, icon: 'none', mask: true }) |
||||
|
reject(res.data) |
||||
|
break |
||||
|
} |
||||
|
}, |
||||
|
fail(err) { |
||||
|
uni.showToast({ title: '网络错误', icon: 'none' }) |
||||
|
reject(err) |
||||
|
}, |
||||
|
complete() { |
||||
|
_this.isLock = false |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
// 验证密码
|
||||
|
export function checkPassword(password: string) { |
||||
|
if (password.trim() === '') return false |
||||
|
|
||||
|
return /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,16}$/.test(password) |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
{ |
||||
|
"extends": "@vue/tsconfig/tsconfig.json", |
||||
|
"compilerOptions": { |
||||
|
"sourceMap": true, |
||||
|
"baseUrl": ".", |
||||
|
"paths": { |
||||
|
"@/*": [ |
||||
|
"./src/*" |
||||
|
] |
||||
|
}, |
||||
|
"lib": [ |
||||
|
"esnext", |
||||
|
"dom" |
||||
|
], |
||||
|
"types": [ |
||||
|
"vite/client", |
||||
|
"@dcloudio/types", |
||||
|
], |
||||
|
"typeRoots": [ |
||||
|
"src/**/*.d.ts" |
||||
|
] |
||||
|
}, |
||||
|
"include": [ |
||||
|
"src/**/*.ts", |
||||
|
"src/**/*.tsx", |
||||
|
"src/**/*.vue", |
||||
|
"src/types/*.d.ts" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
import { defineConfig, loadEnv } from 'vite' |
||||
|
import uni from '@dcloudio/vite-plugin-uni' |
||||
|
import AutoImport from 'unplugin-auto-import/vite' |
||||
|
|
||||
|
import path from 'path' |
||||
|
const pathSrc = path.resolve(__dirname, 'src') |
||||
|
|
||||
|
// https://vitejs.dev/config/
|
||||
|
export default defineConfig(({ mode }) => { |
||||
|
const { VITE_APP_BASE_URL, VITE_APP_BASE_PRE } = loadEnv(mode, process.cwd()) |
||||
|
|
||||
|
return { |
||||
|
transpileDependencies: ['uview-plus'], |
||||
|
resolve: { |
||||
|
// 别名
|
||||
|
alias: { |
||||
|
'@': path.join(__dirname, './src') |
||||
|
} |
||||
|
}, |
||||
|
plugins: [ |
||||
|
uni(), |
||||
|
AutoImport({ |
||||
|
// imports: ['vue', 'uni-app', { 'feng-uniapp-exploit': ['default'] }, { 'src/utils': ['default'] }],
|
||||
|
imports: ['vue', 'uni-app'], |
||||
|
vueTemplate: true, |
||||
|
dts: path.resolve(pathSrc, 'types', 'auto-imports.d.ts') |
||||
|
}) |
||||
|
], |
||||
|
// build: {
|
||||
|
// rollupOptions: {
|
||||
|
// external: ['feng-exploit-plus']
|
||||
|
// }
|
||||
|
// },
|
||||
|
server: { |
||||
|
proxy: { |
||||
|
[VITE_APP_BASE_PRE]: { |
||||
|
target: VITE_APP_BASE_URL, |
||||
|
ws: true, |
||||
|
changeOrigin: true, |
||||
|
rewrite: (path) => path.replace(new RegExp('^' + VITE_APP_BASE_PRE), '') |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||