@ -0,0 +1,5 @@ |
|||||
|
ENV='development' |
||||
|
# base api |
||||
|
VITE_APP_BASE_URL = 'http://pos-api.lingji.vip' |
||||
|
VITE_APP_BASE_PRE = '/shenname' |
||||
|
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,28 @@ |
|||||
|
.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 |
||||
@ -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,30 @@ |
|||||
|
## 项目介绍 |
||||
|
|
||||
|
[uniapp-vue-vite-ts](https://gitee.com/lxxlalala/uniapp-vue-vite-ts) 是基于 Vue3 + Vite4+ TypeScript + uview-plus V3 + Pinia 等最新主流技术栈构建的uniapp前端模板。 |
||||
|
|
||||
|
| 环境 | 名称版本 | |
||||
|
| -------------------- | :----------------------------------------------------------- | |
||||
|
| **开发工具** | VSCode | |
||||
|
| **运行环境** | Node 16+ | |
||||
|
| **VSCode插件(必装)** | 1. `Vue Language Features (Volar) ` <br/>2. `TypeScript Vue Plugin (Volar) ` <br/>3. 禁用 Vetur <br/>4.ESLint <br/>5.Prettier - Code formatter | |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 项目启动 |
||||
|
|
||||
|
```bash |
||||
|
# 安装 pnpm |
||||
|
npm install pnpm -g |
||||
|
|
||||
|
# 安装依赖 |
||||
|
pnpm install |
||||
|
|
||||
|
# 启动运行 |
||||
|
pnpm run dev:h5 (或者查看package.json运行对应平台命令) |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 项目文档 |
||||
|
|
||||
|
- [ESLint+Prettier+Husky 约束和统一前端代码规范](https://blog.csdn.net/qq_51091386/article/details/132099829) |
||||
@ -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,98 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export interface sendCodeType { |
||||
|
phone: number | string |
||||
|
} |
||||
|
|
||||
|
export function sendCode(data: sendCodeType) { |
||||
|
return request.http({ |
||||
|
url: '/api/t.sms/sendCode', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 上传图片
|
||||
|
export function uploadFile(file: any) { |
||||
|
let url = '' |
||||
|
// #ifdef APP-PLUS
|
||||
|
url = import.meta.env.VITE_APP_BASE_URL |
||||
|
// #endif
|
||||
|
// #ifdef H5
|
||||
|
url = import.meta.env.VITE_APP_BASE_PRE |
||||
|
// #endif
|
||||
|
return new Promise((resolve, reject) => { |
||||
|
uni.uploadFile({ |
||||
|
url: `${url}/api/resources/upload`, |
||||
|
filePath: file, |
||||
|
name: 'file', |
||||
|
success: (res) => { |
||||
|
resolve(JSON.parse(res.data)) |
||||
|
}, |
||||
|
fail: (res) => { |
||||
|
reject(res) |
||||
|
} |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 根据 KEY 获取对应数据
|
||||
|
export function getKeyData(key: string) { |
||||
|
return request.http({ |
||||
|
url: '/api/t.systemData/getCategoryByKey', |
||||
|
data: { key: key } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 根据 KEY 获取对应系统设置
|
||||
|
export function getKeySetting(key: string) { |
||||
|
return request.http({ |
||||
|
url: '/api/t.systemData/getSettingByKey', |
||||
|
data: { key: key } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取无限极分类数据
|
||||
|
export function getCategoryData() { |
||||
|
return request.http({ |
||||
|
url: '/api/t.systemData/categoryTree' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 意见反馈
|
||||
|
export interface feedbackType { |
||||
|
type: useType |
||||
|
category_id: number |
||||
|
content: string |
||||
|
image?: string |
||||
|
contact_information: string |
||||
|
} |
||||
|
|
||||
|
export function feedback(data: feedbackType) { |
||||
|
return request.http({ |
||||
|
url: '/api/t.feedback/add', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 购买支付接口
|
||||
|
export function pay(data: { policy_id: number; uid: number; pay_amount: number; version: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/t.notify/buyAgentPolicyNotify', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 直采列表
|
||||
|
export function voucherQuery() { |
||||
|
return request.http({ |
||||
|
url: '/api/d.pickGiftBag/query' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 直采支付
|
||||
|
export function voucherPay(data: { id: number }) { |
||||
|
return request.http({ |
||||
|
url: '/api/d.pickGiftBag/buy', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,147 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'; |
||||
|
import { ref, reactive, toRefs, nextTick, onMounted } from 'vue' |
||||
|
|
||||
|
type argument = { |
||||
|
customListType?: 'default' | 'custom' | 'scroll' |
||||
|
isPerformSearch?: boolean |
||||
|
isPullDownRefresh?: boolean |
||||
|
onFormSearch: (formData: any, onSuccess: Function) => void |
||||
|
onRender?: Function |
||||
|
options?: { [n: string]: string | number | boolean } |
||||
|
emptyText?: string |
||||
|
emptyHeight?: number |
||||
|
} |
||||
|
|
||||
|
const props = withDefaults(defineProps<argument>(), { |
||||
|
customListType: 'default', |
||||
|
isPerformSearch: true, |
||||
|
isPullDownRefresh: true, |
||||
|
onFormSearch: () => { |
||||
|
console.log('onFormSearch') |
||||
|
}, |
||||
|
onRender: () => { |
||||
|
console.log('onRender') |
||||
|
}, |
||||
|
options: () => { |
||||
|
return {} |
||||
|
}, |
||||
|
emptyText: '暂无数据~', |
||||
|
emptyHeight: 60 |
||||
|
}) |
||||
|
|
||||
|
let { options, isPerformSearch, isPullDownRefresh, onFormSearch, onRender } = toRefs(props) |
||||
|
|
||||
|
const list = ref<any[]>([]) |
||||
|
const status = ref('loading') |
||||
|
const initing = ref(true) |
||||
|
const loading = ref(true) |
||||
|
const query = reactive({ |
||||
|
page: 1, |
||||
|
limit: 10, |
||||
|
total: 0 |
||||
|
}) |
||||
|
|
||||
|
const loadData = (callback?: Function) => { |
||||
|
uni.showLoading({ title: '数据加载中' }) |
||||
|
loading.value = true |
||||
|
const params = { ...query, ...options.value } as { [n: string]: string | number | boolean } |
||||
|
delete params.total |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
onFormSearch.value(params, ({ data }: { data: { data: any; total: number } }) => { |
||||
|
loading.value = false |
||||
|
initing.value = false |
||||
|
callback && callback() |
||||
|
query.page = params.page as number |
||||
|
query.limit = params.limit as number |
||||
|
query.total = data.total || 0 |
||||
|
list.value = [...list.value, ...data.data] |
||||
|
|
||||
|
status.value = query.page * query.limit >= query.total ? 'nomore' : 'loading' |
||||
|
|
||||
|
onRender.value && onRender.value(data) |
||||
|
|
||||
|
uni.hideLoading() |
||||
|
}) |
||||
|
}, 100) |
||||
|
} |
||||
|
|
||||
|
const refreshFn = (callback?: Function) => { |
||||
|
query.page = 1 |
||||
|
query.total = 0 |
||||
|
list.value = [] |
||||
|
initing.value = true |
||||
|
loadData(callback) |
||||
|
} |
||||
|
|
||||
|
const onScrolltolower = () => { |
||||
|
if (query.page * query.limit >= query.total) { |
||||
|
status.value = 'nomore' |
||||
|
} else { |
||||
|
if (loading.value) return |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
status.value = 'loading' |
||||
|
query.page += 1 |
||||
|
loadData() |
||||
|
}, 1000) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
onMounted(() => { |
||||
|
if (isPerformSearch.value) { |
||||
|
nextTick(() => { |
||||
|
refreshFn() |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
onPullDownRefresh(() => { |
||||
|
if (isPullDownRefresh.value) refreshFn(() => uni.stopPullDownRefresh()) |
||||
|
}) |
||||
|
|
||||
|
onReachBottom(() => { |
||||
|
if (props.customListType !== 'scroll') { |
||||
|
onScrolltolower() |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
defineExpose({ |
||||
|
list, |
||||
|
refreshFn |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<view v-if="!initing"> |
||||
|
<block v-if="list.length > 0"> |
||||
|
<template v-if="customListType === 'custom'"> |
||||
|
<slot v-bind:data="list" /> |
||||
|
<u-loadmore :status="status" /> |
||||
|
</template> |
||||
|
<template v-else-if="customListType === 'scroll'"> |
||||
|
<scroll-view class="scroll-view" scroll-y @scrolltolower="onScrolltolower"> |
||||
|
<view v-for="(item, index) in list" :key="index"> |
||||
|
<slot v-bind:row="item" v-bind:index="index" /> |
||||
|
</view> |
||||
|
<u-loadmore :status="status" /> |
||||
|
</scroll-view> |
||||
|
</template> |
||||
|
<template v-else> |
||||
|
<view v-for="(item, index) in list" :key="index"> |
||||
|
<slot v-bind:row="item" v-bind:index="index" /> |
||||
|
</view> |
||||
|
<u-loadmore :status="status" /> |
||||
|
</template> |
||||
|
</block> |
||||
|
<ex-empty v-show="list.length <= 0 && status === 'nomore'" :height="emptyHeight" :tips="emptyText" /> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.scroll-view { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,61 @@ |
|||||
|
<template> |
||||
|
<view class="tag_box flex-center-start" :style="{ '--borderColor': borderColor }"> |
||||
|
<view class="border" :style="borderStyle" /> |
||||
|
<text :style="{ color: labelColor }">{{ label }}</text> |
||||
|
<view class="flex1"> |
||||
|
<slot></slot> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
interface tagsInt { |
||||
|
label: string |
||||
|
labelColor?: string |
||||
|
borderColor?: string |
||||
|
borderType?: 'round' | 'line' |
||||
|
} |
||||
|
|
||||
|
const props = withDefaults(defineProps<tagsInt>(), { |
||||
|
label: '收益', |
||||
|
labelColor: '#616161', |
||||
|
borderColor: '#ff8d1a', |
||||
|
borderType: 'line' |
||||
|
}) |
||||
|
|
||||
|
const borderStyle = computed(() => { |
||||
|
if (props.borderType === 'line') { |
||||
|
return { |
||||
|
width: '8rpx', |
||||
|
height: '28rpx', |
||||
|
marginRight: '16rpx' |
||||
|
} |
||||
|
} else { |
||||
|
return { |
||||
|
width: '16rpx', |
||||
|
height: '16rpx', |
||||
|
marginRight: '13rpx' |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.tag_box { |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 400; |
||||
|
line-height: 40rpx; |
||||
|
--borderColor: #ff8d1a; |
||||
|
|
||||
|
.border { |
||||
|
width: 8rpx; |
||||
|
height: 28rpx; |
||||
|
border-radius: 90rpx; |
||||
|
background-color: var(--borderColor); |
||||
|
} |
||||
|
|
||||
|
> .flex1 { |
||||
|
padding-left: 20rpx; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,13 @@ |
|||||
|
export const Prefix = 'POS_' |
||||
|
|
||||
|
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,128 @@ |
|||||
|
/* |
||||
|
* @description: 分页请求 |
||||
|
* @fileName: useListLoadClass.ts |
||||
|
* @author: lxx |
||||
|
* @date: 2023-07-08 08:55:52 |
||||
|
* @version: V1.0.0 |
||||
|
*/ |
||||
|
import { ref } from 'vue' |
||||
|
|
||||
|
class PaginationLoader<T> { |
||||
|
// 分页数据
|
||||
|
private data = ref<T[]>([]) |
||||
|
|
||||
|
// 分页基础参数
|
||||
|
private requestParams = { |
||||
|
page: 1, |
||||
|
limit: 10 |
||||
|
} |
||||
|
|
||||
|
// 是否正在加载
|
||||
|
private isLoading = ref(false) |
||||
|
|
||||
|
// 是否还有更多数据
|
||||
|
private hasMore = ref(true) |
||||
|
|
||||
|
// 请求函数(由外部传入)
|
||||
|
private fetchFn: (formData: Object, onSuccess: Function) => Function |
||||
|
|
||||
|
constructor(fetchFn: (formData: Object, onSuccess: Function) => Function) { |
||||
|
this.fetchFn = fetchFn |
||||
|
} |
||||
|
|
||||
|
// 获取当前数据
|
||||
|
get dataList() { |
||||
|
return this.data.value |
||||
|
} |
||||
|
|
||||
|
// 获取是否正在加载
|
||||
|
get loading() { |
||||
|
return this.isLoading.value |
||||
|
} |
||||
|
|
||||
|
// 获取是否还有更多数据
|
||||
|
get more() { |
||||
|
return this.hasMore.value |
||||
|
} |
||||
|
|
||||
|
// 加载下一页数据
|
||||
|
async loadNextPage() { |
||||
|
// if (this.isLoading.value || !this.hasMore.value) return
|
||||
|
|
||||
|
// uni.showLoading({ title: '加载中...' })
|
||||
|
|
||||
|
// this.isLoading.value = true
|
||||
|
|
||||
|
// try {
|
||||
|
// const result = await this.fetchFn(this.currentPage.value, this.pageSize)
|
||||
|
|
||||
|
// if (result.length > 0) {
|
||||
|
// this.data.value = [...this.data.value, ...result]
|
||||
|
// this.currentPage.value += 1
|
||||
|
// } else {
|
||||
|
// this.hasMore.value = false // 没有更多数据
|
||||
|
// }
|
||||
|
// } catch (error) {
|
||||
|
// console.error('加载数据失败:', error)
|
||||
|
// } finally {
|
||||
|
// this.isLoading.value = false
|
||||
|
// }
|
||||
|
uni.showLoading({ title: '数据加载中' }) |
||||
|
this.isLoading.value = false |
||||
|
const params = { ...this.requestParams } as { [n: string]: string | number | boolean } |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
this.fetchFn(params, ({ data }: { data: { data: any; total: number } }) => { |
||||
|
this.isLoading.value = true |
||||
|
this.requestParams.page = params.page as number |
||||
|
this.requestParams.limit = params.limit as number |
||||
|
this.data.value = [...this.data.value, ...data.data] |
||||
|
uni.hideLoading() |
||||
|
}) |
||||
|
}, 100) |
||||
|
} |
||||
|
|
||||
|
// 重置分页状态
|
||||
|
reset() { |
||||
|
this.data.value = [] |
||||
|
this.requestParams.page = 1 |
||||
|
this.hasMore.value = true |
||||
|
this.isLoading.value = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// export default PaginationLoader
|
||||
|
|
||||
|
const fetchData = async (formData: any, onSuccess: Function) => { |
||||
|
const submitData = { ...formData } |
||||
|
point_order_list(submitData).then((res) => { |
||||
|
const { data } = res as { data: { data: any; total: number } } |
||||
|
onSuccess({ data }) |
||||
|
}) |
||||
|
// // 模拟接口请求
|
||||
|
// return new Promise<{ id: number; name: string }[]>((resolve) => {
|
||||
|
// setTimeout(() => {
|
||||
|
// const data = Array.from({ length: pageSize }, (_, index) => ({
|
||||
|
// id: (page - 1) * pageSize + index,
|
||||
|
// name: `Item ${(page - 1) * pageSize + index}`
|
||||
|
// }))
|
||||
|
// resolve(data)
|
||||
|
// }, 1000)
|
||||
|
// })
|
||||
|
} |
||||
|
|
||||
|
// 创建分页加载实例
|
||||
|
const paginationLoader = new PaginationLoader(fetchData) |
||||
|
|
||||
|
// 加载下一页数据
|
||||
|
paginationLoader.loadNextPage(formDate.value) |
||||
|
|
||||
|
// 初始化加载第一页数据
|
||||
|
paginationLoader.loadNextPage() |
||||
|
|
||||
|
return { |
||||
|
dataList: paginationLoader.dataList, |
||||
|
loading: paginationLoader.loading, |
||||
|
more: paginationLoader.more, |
||||
|
loadNextPage |
||||
|
} |
||||
@ -0,0 +1,125 @@ |
|||||
|
/* |
||||
|
* @description: 分页请求 |
||||
|
* @fileName: useListLoadClass.ts |
||||
|
* @author: lxx |
||||
|
* @date: 2023-07-08 08:55:52 |
||||
|
* @version: V1.0.0 |
||||
|
*/ |
||||
|
import { ref, computed } from 'vue' |
||||
|
import { onReachBottom } from '@dcloudio/uni-app' |
||||
|
|
||||
|
class LoadDataClass { |
||||
|
// 请求参数
|
||||
|
static queryParams = { |
||||
|
page: 1, |
||||
|
limit: 10 |
||||
|
} |
||||
|
// 列表数据
|
||||
|
list = ref<any[]>([]) |
||||
|
total = ref(0) |
||||
|
// 前置处理方法
|
||||
|
afterLoadData: Function | undefined |
||||
|
// 请求方法
|
||||
|
Query: Function |
||||
|
// 加载状态参数
|
||||
|
isLoading = ref(false) |
||||
|
// 无更多数据了
|
||||
|
isNoData = computed(() => { |
||||
|
if (LoadDataClass.queryParams.page * LoadDataClass.queryParams.limit >= this.total.value) { |
||||
|
return true |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
}) |
||||
|
// 显示暂无数据
|
||||
|
isEmpty = computed(() => { |
||||
|
if (this.total.value === 0) { |
||||
|
return true |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
constructor(apiFunctions: Function, afterLoadData?: Function, options?: any) { |
||||
|
this.Query = apiFunctions |
||||
|
this.afterLoadData = afterLoadData |
||||
|
// 存在额外参数拼接
|
||||
|
if (options) { |
||||
|
LoadDataClass.queryParams = { ...LoadDataClass.queryParams, ...options } |
||||
|
} |
||||
|
// 加载数据
|
||||
|
this.LoadData() |
||||
|
} |
||||
|
// 加载数据
|
||||
|
LoadData = async () => { |
||||
|
uni.showLoading({ |
||||
|
title: '加载中...' |
||||
|
}) |
||||
|
this.isLoading.value = true |
||||
|
const res = await this.Query(LoadDataClass.queryParams) |
||||
|
this.afterLoadData && this.afterLoadData(res) |
||||
|
this.total.value = res.data.total |
||||
|
this.list.value = this.list.value.concat(res.data.data) |
||||
|
|
||||
|
uni.hideLoading() |
||||
|
uni.stopPullDownRefresh() |
||||
|
this.isLoading.value = false |
||||
|
} |
||||
|
// 加载更多
|
||||
|
LoadMore = () => { |
||||
|
if (this.isNoData.value || this.isLoading.value) return // 无数据或者加载中不进行加载
|
||||
|
LoadDataClass.queryParams.page += 1 |
||||
|
this.LoadData() |
||||
|
} |
||||
|
// 重置参数
|
||||
|
queryParamsReset = () => { |
||||
|
LoadDataClass.queryParams = { |
||||
|
page: 1, |
||||
|
limit: 10 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 刷新 |
||||
|
* @param isClear: 是否清空数据 |
||||
|
*/ |
||||
|
ReLoad = (isClear: boolean = true) => { |
||||
|
this.isLoading.value = false |
||||
|
this.list.value = [] |
||||
|
if (isClear) { |
||||
|
this.queryParamsReset() |
||||
|
} else { |
||||
|
LoadDataClass.queryParams.page = 1 |
||||
|
} |
||||
|
|
||||
|
this.LoadData() |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* 分页加载数据方法 |
||||
|
* @param api: ListAPI 方法 |
||||
|
* @param afterLoadData: res数据前置处理方法 |
||||
|
* @returns |
||||
|
*/ |
||||
|
interface LoadDataInt { |
||||
|
api: Function |
||||
|
afterLoadData?: Function |
||||
|
options?: any |
||||
|
} |
||||
|
|
||||
|
export function LoadData({ api, afterLoadData, options }: LoadDataInt) { |
||||
|
const data = new LoadDataClass(api, afterLoadData, options) |
||||
|
|
||||
|
// 下拉加载
|
||||
|
onReachBottom(() => { |
||||
|
console.log('onReachBottom') |
||||
|
data.LoadMore() |
||||
|
}) |
||||
|
return { |
||||
|
list: data.list, |
||||
|
isLoading: data.isLoading, |
||||
|
isNoData: data.isNoData, |
||||
|
isEmpty: data.isEmpty, |
||||
|
ReLoad: data.ReLoad |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,127 @@ |
|||||
|
import { ref, reactive, computed } from 'vue' |
||||
|
import { onReachBottom } from '@dcloudio/uni-app' |
||||
|
/* |
||||
|
* @description: 分页请求 |
||||
|
* @fileName: useListLoadClass.ts |
||||
|
* @author: lxx |
||||
|
* @date: 2023-07-08 08:55:52 |
||||
|
* @version: V1.0.0 |
||||
|
* loading状态 |
||||
|
* @param {*} Query 请求函数 |
||||
|
* @param {*} LoadData 加载数据方法 |
||||
|
* @param {*} ReLoad (isClear?: boolean) 刷新列表数据 isClear 传入true时将请求参数(queryParams)还原初始化状态 |
||||
|
*/ |
||||
|
|
||||
|
export function usePagingLoad(Query: any) { |
||||
|
// 下拉加载
|
||||
|
onReachBottom(() => { |
||||
|
console.log('onReachBottom') |
||||
|
loadMore() |
||||
|
}) |
||||
|
|
||||
|
const isLoading = ref(false) |
||||
|
let queryParams = reactive({} as any) |
||||
|
|
||||
|
queryParams = { |
||||
|
page: 1, |
||||
|
limit: 10 |
||||
|
} |
||||
|
|
||||
|
const total = ref(0) |
||||
|
|
||||
|
const list = ref([]) |
||||
|
// 无更多数据了
|
||||
|
const isNoData = computed(() => { |
||||
|
if (queryParams.page * queryParams.limit >= total.value) { |
||||
|
return true |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
}) |
||||
|
// 显示暂无数据
|
||||
|
const isEmpty = computed(() => { |
||||
|
if (total.value === 0) { |
||||
|
return true |
||||
|
} else { |
||||
|
return false |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
interface optionInt { |
||||
|
key: string |
||||
|
val: any |
||||
|
} |
||||
|
|
||||
|
const LoadData = async (afterLoadData?: any, option?: optionInt[]) => { |
||||
|
const obj: any = {} |
||||
|
console.log('option', option) |
||||
|
if (option && option?.length > 0) { |
||||
|
option?.map((item) => { |
||||
|
obj[item?.key] = item.val |
||||
|
}) |
||||
|
} |
||||
|
// , ...rest: any[]
|
||||
|
// if (rest.length > 0) {
|
||||
|
// rest.map((item) => {
|
||||
|
// obj[item?.key] = item?.val;
|
||||
|
// });
|
||||
|
// }
|
||||
|
queryParams = reactive({ ...queryParams, ...obj }) |
||||
|
|
||||
|
uni.showLoading({ |
||||
|
title: '加载中...' |
||||
|
}) |
||||
|
isLoading.value = true |
||||
|
const res = await Query(queryParams) |
||||
|
total.value = res?.data?.total |
||||
|
|
||||
|
// 数据加载完成后 设置 after 钩子
|
||||
|
afterLoadData && afterLoadData(res.data) |
||||
|
console.log('res.data', res.data) |
||||
|
|
||||
|
list.value = list.value.concat(res?.data?.data) |
||||
|
uni.hideLoading() |
||||
|
uni.stopPullDownRefresh() |
||||
|
isLoading.value = false |
||||
|
} |
||||
|
|
||||
|
// const afterLoadData = (data: any) => {
|
||||
|
// console.log(data);
|
||||
|
// };
|
||||
|
|
||||
|
const ReLoad = (option?: optionInt[], isClear?: boolean) => { |
||||
|
isLoading.value = false |
||||
|
list.value = [] |
||||
|
if (isClear) { |
||||
|
queryParams = reactive({ |
||||
|
page: 1, |
||||
|
limit: 10 |
||||
|
}) |
||||
|
} else { |
||||
|
queryParams.page = 1 |
||||
|
} |
||||
|
const obj: any = {} |
||||
|
if (option && option?.length > 0) { |
||||
|
option?.map((item) => { |
||||
|
obj[item?.key] = item.val |
||||
|
}) |
||||
|
} |
||||
|
queryParams = reactive({ ...queryParams, ...obj }) |
||||
|
LoadData() |
||||
|
} |
||||
|
|
||||
|
const loadMore = () => { |
||||
|
if (isNoData.value || isLoading.value) return // 无数据或者加载中不进行加载
|
||||
|
queryParams.page += 1 |
||||
|
LoadData() |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
list, |
||||
|
LoadData, |
||||
|
ReLoad, |
||||
|
isNoData, |
||||
|
isEmpty, |
||||
|
isLoading |
||||
|
} |
||||
|
} |
||||
@ -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__1AE1F37", |
||||
|
"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" : "wxd448c878a54da98d", |
||||
|
"UniversalLinks" : "" |
||||
|
} |
||||
|
}, |
||||
|
"geolocation" : { |
||||
|
"amap" : { |
||||
|
"name" : "amap_18648278829CcsBXVUm1", |
||||
|
"__platform__" : [ "ios", "android" ], |
||||
|
"appkey_ios" : "435934cdfcc901e4872a70391d92cccd", |
||||
|
"appkey_android" : "435934cdfcc901e4872a70391d92cccd" |
||||
|
} |
||||
|
}, |
||||
|
"maps" : { |
||||
|
"amap" : { |
||||
|
"name" : "amap_18648278829CcsBXVUm1", |
||||
|
"appkey_ios" : "435934cdfcc901e4872a70391d92cccd", |
||||
|
"appkey_android" : "435934cdfcc901e4872a70391d92cccd" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
"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" : "C:/Users/Lenovo/Desktop/480x762.9/res/drawable-xhdpi/480x762.9.png", |
||||
|
"xhdpi" : "C:/Users/Lenovo/Desktop/720x1242.9/res/drawable-xhdpi/720x1242.9.png", |
||||
|
"xxhdpi" : "C:/Users/Lenovo/Desktop/1080x1882.9/res/drawable-xhdpi/1080x1882.9.png" |
||||
|
}, |
||||
|
"ios" : { |
||||
|
"storyboard" : "C:/Users/Lenovo/Desktop/CustomStoryboard.zip" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
/* 快应用特有相关 */ |
||||
|
"quickapp" : {}, |
||||
|
/* 小程序特有相关 */ |
||||
|
"mp-weixin" : { |
||||
|
"appid" : "", |
||||
|
"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,111 @@ |
|||||
|
{ |
||||
|
"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/votingElection/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "投票选举", |
||||
|
"enablePullDownRefresh": true |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"path": "pages/electionList/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "选举列表", |
||||
|
"enablePullDownRefresh": false |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"path": "pages/electionResults/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "选举结果", |
||||
|
"navigationBarTextStyle": "white", |
||||
|
"enablePullDownRefresh": false |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"path": "pages/myElection/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "我的选举", |
||||
|
"navigationBarTextStyle": "white", |
||||
|
"enablePullDownRefresh": false |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"name": "links", |
||||
|
"path": "pages/index/links", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "外部链接", |
||||
|
"enablePullDownRefresh": false |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"name": "guide", |
||||
|
"path": "pages/index/guide", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "用户指南", |
||||
|
"enablePullDownRefresh": false, |
||||
|
"navigationStyle": "custom" |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"name": "user", |
||||
|
"path": "pages/mine/index", |
||||
|
"style": { |
||||
|
"navigationBarTitleText": "个人信息", |
||||
|
"enablePullDownRefresh": false, |
||||
|
"navigationStyle": "custom" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"globalStyle": { |
||||
|
"navigationBarTextStyle": "black", |
||||
|
"navigationBarTitleText": "uni-app", |
||||
|
"navigationBarBackgroundColor": "#F8F8F8", |
||||
|
"backgroundColor": "#F8F8F8" |
||||
|
}, |
||||
|
"tabBar": { |
||||
|
"color": "#9CA3AF", |
||||
|
"selectedColor": "#2563EB", |
||||
|
"borderStyle": "white", |
||||
|
"backgroundColor": "#F9FAFB", |
||||
|
"list": [ |
||||
|
{ |
||||
|
"pagePath": "pages/votingElection/index", |
||||
|
"iconPath": "static/tabbar/tpxj.png", |
||||
|
"selectedIconPath": "static/tabbar/tpxj-select.png", |
||||
|
"text": "投票选举" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/electionList/index", |
||||
|
"iconPath": "static/tabbar/xjlb.png", |
||||
|
"selectedIconPath": "static/tabbar/xjlb-select.png", |
||||
|
"text": "选举列表" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/electionResults/index", |
||||
|
"iconPath": "static/tabbar/xjjg.png", |
||||
|
"selectedIconPath": "static/tabbar/xjjg-select.png", |
||||
|
"text": "选举结果" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/myElection/index", |
||||
|
"iconPath": "static/tabbar/wdxj.png", |
||||
|
"selectedIconPath": "static/tabbar/wdxj-select.png", |
||||
|
"text": "我的选举" |
||||
|
}, |
||||
|
{ |
||||
|
"pagePath": "pages/mine/index", |
||||
|
"iconPath": "static/tabbar/grxx.png", |
||||
|
"selectedIconPath": "static/tabbar/grxx-select.png", |
||||
|
"text": "个人信息" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,218 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import EcList from '@/components/ex-list/ex-list.vue' |
||||
|
const doSearch = (_formData: { page: number; limit: number }, onSuccess: Function) => { |
||||
|
onSuccess({ |
||||
|
data: { |
||||
|
data:[ |
||||
|
{ name: '测试一' }, |
||||
|
{ name: '测试二' } |
||||
|
], |
||||
|
total: 4 |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<view class="electionList"> |
||||
|
<EcList 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">{{ '2024年度学生会主席选举' }}</text> |
||||
|
<text class="status b">进行中</text> |
||||
|
<!-- <text class="status f">未开始</text> --> |
||||
|
<!-- <text class="status e">已结束</text> --> |
||||
|
</view> |
||||
|
<view class="time">{{ '投票时间:2024-03-01 至 2024-03-07' }}</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"> |
||||
|
<view class="head"></view> |
||||
|
<view class="content flex1"> |
||||
|
<view class="name flex-center-start"> |
||||
|
<text>陈佳怡</text> |
||||
|
<!-- <text class="status">当选</text> --> |
||||
|
<text class="status un">未当选</text> |
||||
|
</view> |
||||
|
<view class="votes">得票数:286</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="progress"> |
||||
|
<u-line-progress :percentage="60" height="8rpx" active-color="#ff0000" :show-text="false" /> |
||||
|
<view class="progress-text">60%</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="flex info-items"> |
||||
|
<view class="head"></view> |
||||
|
<view class="content flex1"> |
||||
|
<view class="name flex-center-start"> |
||||
|
<text>陈佳怡</text> |
||||
|
<text class="status">当选</text> |
||||
|
<!-- <text class="status un">未当选</text> --> |
||||
|
</view> |
||||
|
<view class="votes">得票数:286</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="progress"> |
||||
|
<u-line-progress :percentage="60" height="8rpx" active-color="#ff0000" :show-text="false" /> |
||||
|
<view class="progress-text">60%</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="info-bts">查看投票详情</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
</EcList> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.electionList { |
||||
|
width: 100%; |
||||
|
box-sizing: border-box; |
||||
|
min-height: calc(100vh - 100rpx); |
||||
|
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,7 @@ |
|||||
|
<template> |
||||
|
<view>选举结果</view> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup></script> |
||||
|
|
||||
|
<style lang="scss" scoped></style> |
||||
@ -0,0 +1,112 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import useUserStore from '@/store/user' |
||||
|
const userStore = useUserStore() |
||||
|
|
||||
|
const phone = ref('') |
||||
|
const kefuRef = ref() |
||||
|
const list = ref< |
||||
|
{ |
||||
|
id?: number |
||||
|
name?: string |
||||
|
guide: { guide_id?: number; title?: string }[] |
||||
|
}[] |
||||
|
>([]) |
||||
|
|
||||
|
const kefuConfirm = () => { |
||||
|
uni.makePhoneCall({ |
||||
|
phoneNumber: phone.value, |
||||
|
success: (response) => { |
||||
|
console.log('success', response) |
||||
|
}, |
||||
|
fail: (err) => { |
||||
|
console.log('fail', err) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const navto = (url: string, params = {}) => uni.$util.goToPage({ url, params }) |
||||
|
|
||||
|
onShow(() => { |
||||
|
// getKeySetting('service_telephone').then(({ data: { value } }: any) => (phone.value = value.trim())) |
||||
|
// listApi().then(({ data }: any) => (list.value = data || [])) |
||||
|
}) |
||||
|
</script> |
||||
|
<template> |
||||
|
<ex-header title="用户指南" /> |
||||
|
<view class="guide-view"> |
||||
|
<view class="kefu-btn flex" @click="kefuRef.show = true"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/customer.png" mode="widthFix" style="width: 40rpx" /> |
||||
|
<text style="margin-left: 14rpx">联系客服</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="pages-view"> |
||||
|
<u-collapse accordion :border="true"> |
||||
|
<block v-for="(v, k) of list" :key="k"> |
||||
|
<u-collapse-item :title="v.name"> |
||||
|
<view |
||||
|
:key="ck" |
||||
|
v-for="(cv, ck) of v.guide" |
||||
|
:class="{ 'pages-view-content': true, 'text-ellipsis': true, border: ck < v.guide.length - 1 }" |
||||
|
@click.stop="navto('pages/setting/agreement', { type: 'guide', id: cv.guide_id })" |
||||
|
> |
||||
|
{{ cv.title }} |
||||
|
</view> |
||||
|
</u-collapse-item> |
||||
|
</block> |
||||
|
</u-collapse> |
||||
|
</view> |
||||
|
|
||||
|
<ex-dialog ref="kefuRef" title="联系客服" show-cancel-button confirm-text="拨号" confirm-color="#43CF7C" @confirm="kefuConfirm"> |
||||
|
<view class="flex column"> |
||||
|
<image style="width: 84rpx" :src="`http://cdn-pos.lingji.vip/static/icon/phone-${userStore.useType}.png`" mode="widthFix" /> |
||||
|
<view style="margin-top: 36rpx; font-size: 60rpx; font-weight: 700; color: #383838; text-align: center"> |
||||
|
{{ phone }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</ex-dialog> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.guide-view { |
||||
|
padding: 26rpx 28rpx; |
||||
|
.kefu-btn { |
||||
|
color: #fff; |
||||
|
padding: 32rpx; |
||||
|
margin-bottom: 26rpx; |
||||
|
background: linear-gradient(90deg, #4778ff 0%, #4778ffb8 100%); |
||||
|
} |
||||
|
.pages-view { |
||||
|
background-color: #fff; |
||||
|
|
||||
|
&-content { |
||||
|
padding: 16rpx; |
||||
|
color: #9a9bad; |
||||
|
text-align: left; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 400; |
||||
|
letter-spacing: 0; |
||||
|
line-height: 48rpx; |
||||
|
|
||||
|
&.border { |
||||
|
border-bottom: 1rpx solid #dbdbdb; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:deep(.u-collapse) { |
||||
|
.u-cell__body { |
||||
|
padding: 24rpx 28rpx; |
||||
|
} |
||||
|
|
||||
|
.u-collapse-item__content__text { |
||||
|
padding: 0 28rpx; |
||||
|
border-bottom: 4rpx solid #f5f5f5 !important; |
||||
|
|
||||
|
&.content-class { |
||||
|
border: none !important; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,9 @@ |
|||||
|
<template> |
||||
|
<web-view :src="url" /> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
const url = ref('') |
||||
|
|
||||
|
onLoad((opt) => (url.value = opt?.url)) |
||||
|
</script> |
||||
@ -0,0 +1,314 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import useUserStore from '@/store/user' |
||||
|
import { getHeaderImage } from '@/utils/common' |
||||
|
|
||||
|
const userStore = useUserStore() |
||||
|
|
||||
|
const OBJ = { |
||||
|
other: [ |
||||
|
{ |
||||
|
label: '地址管理', |
||||
|
icon: 'position', |
||||
|
url: 'pages/address/index' |
||||
|
}, |
||||
|
{ |
||||
|
label: '用户指南', |
||||
|
icon: 'guide', |
||||
|
url: 'pages/index/guide' |
||||
|
}, |
||||
|
{ |
||||
|
label: '意见反馈', |
||||
|
icon: 'suggest', |
||||
|
url: 'pages/feedback/index' |
||||
|
}, |
||||
|
{ |
||||
|
label: '设置', |
||||
|
icon: 'setting', |
||||
|
url: 'pages/setting/index' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
|
||||
|
const { statusBarHeight } = uni.getSystemInfoSync() |
||||
|
|
||||
|
const userphone = computed(() => uni.$util.hidePhone(userStore.userInfo.phone || '17612341234')) |
||||
|
|
||||
|
const data = reactive({ |
||||
|
cumulative: '', |
||||
|
estimate: 0, |
||||
|
formalities: 0 |
||||
|
}) |
||||
|
|
||||
|
const navto = (url: string, params = {}) => uni.$util.goToPage({ url, params }) |
||||
|
</script> |
||||
|
<template> |
||||
|
<view class="user-container"> |
||||
|
<view class="header-box" :style="{ paddingTop: `${(statusBarHeight as number) * 2 + 20}rpx` }"> |
||||
|
<view class="title">我的</view> |
||||
|
<view class="flex user-box" @click="navto('pages/mine/info')"> |
||||
|
<view class="headimg"> |
||||
|
<image class="img" :src="getHeaderImage(userStore.userInfo.head_image)" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="flex-start-evenly column"> |
||||
|
<view class="name">{{ userStore?.userInfo?.nickname || '' }}</view> |
||||
|
<view class="phone">{{ userphone }}</view> |
||||
|
</view> |
||||
|
<view class="flex1 flex-center-end"> |
||||
|
<u-icon name="arrow-right" size="14" color="#fff" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="options flex-center-evenly"> |
||||
|
<view class="flex" @click="navto('pages/mine/wallet')"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/mine/kb.png" mode="heightFix" /> |
||||
|
<text>钱包</text> |
||||
|
</view> |
||||
|
<view class="options-line"></view> |
||||
|
<view class="flex" @click="navto('pages/mine/revenue')"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/mine/sr.png" mode="heightFix" /> |
||||
|
<text>收入明细</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="report"> |
||||
|
<view class="report-title">我的省钱报告</view> |
||||
|
<view class="flex" style="margin-bottom: 32rpx"> |
||||
|
<view style="margin-right: 100rpx"> |
||||
|
<view class="report-tip">累计节省手续费</view> |
||||
|
<u-count-to ref="uCountTo" :end-val="data.formalities" color="#fff" font-size="36rpx" /> |
||||
|
</view> |
||||
|
<view style="margin-right: auto"> |
||||
|
<view class="report-tip">预计最高还能省</view> |
||||
|
<u-count-to ref="uCountTo" :end-val="data.estimate" color="#fff" font-size="36rpx" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="report-tip" style="color: #fff"> |
||||
|
<text>累计综合收款费率</text> |
||||
|
<text class="report-price">{{ data.cumulative }}%</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="option-list"> |
||||
|
<view class="option-list-head flex-center-between"> |
||||
|
<view class="option-list-head-title">我的订单</view> |
||||
|
<view class="option-list-head-tip flex" @click="navto('pages/order/list')"> |
||||
|
<text>查看全部</text> |
||||
|
<u-icon name="arrow-right" size="16" color="#DEDEDE" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="option-list-body"> |
||||
|
<view class="flex column" @click="navto('pages/order/list', { status: 'unpaid' })"> |
||||
|
<view class="img-box bg flex"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/mine/besent.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="text">待付款</view> |
||||
|
</view> |
||||
|
<view class="flex column" @click="navto('pages/order/list', { status: 'paid' })"> |
||||
|
<view class="img-box bg flex"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/mine/unsend.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="text">待发货</view> |
||||
|
</view> |
||||
|
<view class="flex column" @click="navto('pages/order/list', { status: 'shipped' })"> |
||||
|
<view class="img-box bg flex"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/mine/received.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="text">待收货</view> |
||||
|
</view> |
||||
|
<view class="flex column" @click="navto('pages/order/list', { status: 'finished' })"> |
||||
|
<view class="img-box bg flex"> |
||||
|
<image src="http://cdn-pos.lingji.vip/static/icon/mine/completed.png" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="text">已完成</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="option-list wb"> |
||||
|
<view class="option-list-head flex-center-between"> |
||||
|
<view class="option-list-head-title">其它</view> |
||||
|
</view> |
||||
|
<view class="option-list-body"> |
||||
|
<block v-for="(v, k) of OBJ.other" :key="k"> |
||||
|
<view class="flex column" @click="navto(v.url)"> |
||||
|
<view class="img-box flex"> |
||||
|
<image :src="`http://cdn-pos.lingji.vip/static/icon/mine/${v.icon}.png`" mode="widthFix" /> |
||||
|
</view> |
||||
|
<view class="text">{{ v.label }}</view> |
||||
|
</view> |
||||
|
</block> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.user-container { |
||||
|
background-color: #fff; |
||||
|
|
||||
|
.header-box { |
||||
|
width: 100%; |
||||
|
background-image: url(http://cdn-pos.lingji.vip/static/images/mine/bg.png); |
||||
|
background-repeat: no-repeat; |
||||
|
background-size: cover; |
||||
|
padding-bottom: 24rpx; |
||||
|
|
||||
|
.title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 500; |
||||
|
color: #fff; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.user-box { |
||||
|
width: 100%; |
||||
|
padding: 0 32rpx; |
||||
|
margin-top: 48rpx; |
||||
|
margin-bottom: 46rpx; |
||||
|
align-items: stretch; |
||||
|
|
||||
|
.headimg { |
||||
|
width: 112rpx; |
||||
|
height: 112rpx; |
||||
|
border-radius: 50%; |
||||
|
background-clip: content-box; |
||||
|
background-color: #000000a6; |
||||
|
border: 10rpx solid rgba(255, 255, 255, 0.3); |
||||
|
overflow: hidden; |
||||
|
position: relative; |
||||
|
margin-right: 22rpx; |
||||
|
|
||||
|
> .img { |
||||
|
width: 120%; |
||||
|
position: absolute; |
||||
|
top: -10%; |
||||
|
left: -10%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.name { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 400; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.phone { |
||||
|
font-size: 14px; |
||||
|
font-weight: 400; |
||||
|
color: #fff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
> .options { |
||||
|
image { |
||||
|
min-width: 32rpx; |
||||
|
height: 36rpx; |
||||
|
margin-right: 24rpx; |
||||
|
} |
||||
|
|
||||
|
text { |
||||
|
color: #fff; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 400; |
||||
|
letter-spacing: 0rpx; |
||||
|
} |
||||
|
|
||||
|
.options-line { |
||||
|
width: 0rpx; |
||||
|
height: 48rpx; |
||||
|
border-right: 2rpx solid #ffffff2e; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.report { |
||||
|
width: calc(100% - 56rpx); |
||||
|
margin: 28rpx 28rpx 8rpx; |
||||
|
border-radius: 8rpx; |
||||
|
padding: 26rpx 26rpx 28rpx; |
||||
|
background-image: url(http://cdn-pos.lingji.vip/static/images/mine/bg1.png); |
||||
|
background-repeat: no-repeat; |
||||
|
background-size: cover; |
||||
|
|
||||
|
&-title { |
||||
|
color: #fff; |
||||
|
text-align: left; |
||||
|
font-size: 36rpx; |
||||
|
font-weight: bold; |
||||
|
font-style: oblique; |
||||
|
line-height: 46rpx; |
||||
|
letter-spacing: 2rpx; |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
&-tip { |
||||
|
font-size: 20rpx; |
||||
|
font-weight: 400; |
||||
|
letter-spacing: 0rpx; |
||||
|
line-height: 29rpx; |
||||
|
color: #ffe9d4; |
||||
|
text-align: left; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.option-list { |
||||
|
padding: 22rpx 28rpx 40rpx; |
||||
|
border-bottom: 16rpx solid #f5f5f5; |
||||
|
|
||||
|
&.wb { |
||||
|
border-color: #fff; |
||||
|
} |
||||
|
|
||||
|
&-head { |
||||
|
margin-bottom: 30rpx; |
||||
|
|
||||
|
&-title { |
||||
|
color: #333; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 400; |
||||
|
line-height: 46rpx; |
||||
|
letter-spacing: 0rpx; |
||||
|
} |
||||
|
|
||||
|
&-tip { |
||||
|
color: #a6a6a6; |
||||
|
font-size: 24rpx; |
||||
|
font-weight: 400; |
||||
|
letter-spacing: 0rpx; |
||||
|
line-height: 35rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&-body { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(4, 1fr); |
||||
|
row-gap: 30rpx; |
||||
|
|
||||
|
.img-box { |
||||
|
width: 80rpx; |
||||
|
height: 80rpx; |
||||
|
border-radius: 16rpx; |
||||
|
|
||||
|
&.bg { |
||||
|
background: #f5f8ff; |
||||
|
} |
||||
|
|
||||
|
image { |
||||
|
width: 58rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.text { |
||||
|
color: #333; |
||||
|
font-size: 26rpx; |
||||
|
font-weight: 400; |
||||
|
text-align: center; |
||||
|
line-height: 38rpx; |
||||
|
letter-spacing: 0rpx; |
||||
|
margin-top: 4rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,7 @@ |
|||||
|
<template> |
||||
|
<view>我的选举</view> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts" setup></script> |
||||
|
|
||||
|
<style lang="scss" scoped></style> |
||||
@ -0,0 +1,338 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
const doSearch = (_formData: { page: number; limit: number }, onSuccess: Function) => { |
||||
|
// const submitData = { ...formData } |
||||
|
// listApi(submitData, userStore.useType).then((res) => { |
||||
|
// const { data } = res as { data: { data: any; total: number } } |
||||
|
// onSuccess({ data }) |
||||
|
// }) |
||||
|
onSuccess({ |
||||
|
data: { |
||||
|
data: [ |
||||
|
{ |
||||
|
img: '/static/img/grxx.png', |
||||
|
name: '陈志远', |
||||
|
class: '现任财务总监' |
||||
|
}, |
||||
|
{ |
||||
|
img: '/static/img/grxx.png', |
||||
|
name: '陈志远', |
||||
|
class: '现任财务总监' |
||||
|
}, |
||||
|
{ |
||||
|
img: '/static/img/grxx.png', |
||||
|
name: '陈志远', |
||||
|
class: '现任财务总监' |
||||
|
}, |
||||
|
{ |
||||
|
img: '/static/img/grxx.png', |
||||
|
name: '陈志远', |
||||
|
class: '现任财务总监' |
||||
|
}, |
||||
|
{ |
||||
|
img: '/static/img/grxx.png', |
||||
|
name: '陈志远', |
||||
|
class: '现任财务总监' |
||||
|
} |
||||
|
], |
||||
|
total: 0 |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
const selectIndex = ref(0) |
||||
|
const buttlist = ref([ |
||||
|
{ |
||||
|
butname: '同意' |
||||
|
}, |
||||
|
{ |
||||
|
butname: '反对' |
||||
|
}, |
||||
|
{ |
||||
|
butname: '弃权' |
||||
|
} |
||||
|
]) |
||||
|
|
||||
|
const selectBut = (index: number) => { |
||||
|
selectIndex.value = index |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<!-- 你的页面内容 --> |
||||
|
<view class="box"> |
||||
|
<ex-list ref="reListRef" custom-list-type="scroll" :on-form-search="doSearch" empty-text=""> |
||||
|
<template v-slot="{ data }"> |
||||
|
<view class="headpart"> |
||||
|
<view class="title">2024年度董事会成员选举</view> |
||||
|
<view class="time">投票开始时间:2024年3月15日 18:00</view> |
||||
|
<view class="time">投票截止时间:2024年3月15日 18:00</view> |
||||
|
</view> |
||||
|
<view class="tppart"> |
||||
|
<view class="tpone" v-for="(row, index) of data" :key="'tpone' + index"> |
||||
|
<view class="topp"> |
||||
|
<img style="width: 96rpx; height: 96rpx; border-radius: 50%" :src="row.img" alt="" /> |
||||
|
<view class="rightpart"> |
||||
|
<view class="name"> |
||||
|
{{ row.name }} |
||||
|
</view> |
||||
|
<view class="class"> |
||||
|
{{ row.class }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<view class="bottomp"> |
||||
|
<view |
||||
|
class="minbut" |
||||
|
v-for="(item, index) in buttlist" |
||||
|
:key="'minbut' + index" |
||||
|
@click="selectBut(index)" |
||||
|
:class="{ active: selectIndex === index }" |
||||
|
> |
||||
|
{{ item.butname }} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
</ex-list> |
||||
|
<view class="bottbutton"> |
||||
|
<view class="qbty">全部同意</view> |
||||
|
<view class="tjtp">提交投票</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.box { |
||||
|
width: 100%; |
||||
|
height: 100vh; |
||||
|
background-color: #f9fafb; |
||||
|
|
||||
|
.headpart { |
||||
|
width: 86%; |
||||
|
height: 194rpx; |
||||
|
border-radius: 24rpx; |
||||
|
background-color: #eff6ff; |
||||
|
margin: 32rpx auto; |
||||
|
padding: 20rpx 3%; |
||||
|
|
||||
|
.title { |
||||
|
color: #2563eb; |
||||
|
font-size: 28rpx; |
||||
|
margin-top: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.time { |
||||
|
margin-top: 16rpx; |
||||
|
color: #4b5563; |
||||
|
font-size: 28rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tppart { |
||||
|
width: 100%; |
||||
|
max-height: 69vh; |
||||
|
overflow-y: auto; |
||||
|
display: grid; |
||||
|
justify-items: center; |
||||
|
|
||||
|
.tpone { |
||||
|
width: 91%; |
||||
|
height: 264rpx; |
||||
|
padding: 20rpx 4%; |
||||
|
box-sizing: border-box; |
||||
|
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 -2rpx rgba(0, 0, 0, 0.1), |
||||
|
0rpx 2rpx 6rpx 0rpx rgba(0, 0, 0, 0.1); |
||||
|
margin-top: 32rpx; |
||||
|
display: grid; |
||||
|
|
||||
|
.topp { |
||||
|
display: flex; |
||||
|
|
||||
|
.rightpart { |
||||
|
margin-left: 32rpx; |
||||
|
display: grid; |
||||
|
justify-items: left; |
||||
|
align-content: baseline; |
||||
|
|
||||
|
.name { |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 500; |
||||
|
line-height: 42rpx; |
||||
|
letter-spacing: normal; |
||||
|
color: #000000; |
||||
|
margin-top: 7rpx; |
||||
|
} |
||||
|
|
||||
|
.class { |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: normal; |
||||
|
line-height: 40rpx; |
||||
|
letter-spacing: normal; |
||||
|
color: #6b7280; |
||||
|
margin-top: 7rpx; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bottomp { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
gap: 0rpx 20rpx; |
||||
|
|
||||
|
.minbut { |
||||
|
flex: 1; |
||||
|
width: 190rpx; |
||||
|
height: 76rpx; |
||||
|
/* 自动布局 */ |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
padding: 16rpx 32rpx; |
||||
|
flex-wrap: wrap; |
||||
|
align-content: flex-start; |
||||
|
border-radius: 8rpx; |
||||
|
background: #ffffff; |
||||
|
box-sizing: border-box; |
||||
|
border: 2rpx solid #d1d5db; |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: normal; |
||||
|
line-height: 40rpx; |
||||
|
text-align: center; |
||||
|
letter-spacing: normal; |
||||
|
color: #4b5563; |
||||
|
} |
||||
|
|
||||
|
.minbut.active { |
||||
|
border: 2rpx solid #2563eb; |
||||
|
color: #2563eb; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tpone:first-child { |
||||
|
margin-top: 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.bottbutton { |
||||
|
width: 100%; |
||||
|
height: 10vh; |
||||
|
display: flex; |
||||
|
padding: 24rpx 32rpx; |
||||
|
gap: 0rpx 24rpx; |
||||
|
flex-wrap: wrap; |
||||
|
align-content: flex-start; |
||||
|
background: #ffffff; |
||||
|
box-sizing: border-box; |
||||
|
border-width: 2rpx 0rpx 0rpx 0rpx; |
||||
|
border-style: solid; |
||||
|
border-color: #f3f4f6; |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
|
||||
|
.qbty { |
||||
|
width: 331rpx; |
||||
|
height: 90rpx; |
||||
|
/* 自动布局 */ |
||||
|
display: flex; |
||||
|
box-sizing: border-box; |
||||
|
justify-content: center; |
||||
|
padding: 24rpx 0rpx; |
||||
|
gap: 0rpx 20rpx; |
||||
|
flex-wrap: wrap; |
||||
|
border-radius: 8rpx; |
||||
|
background: #eff6ff; |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 500; |
||||
|
line-height: 42rpx; |
||||
|
text-align: center; |
||||
|
letter-spacing: normal; |
||||
|
color: #2563eb; |
||||
|
} |
||||
|
|
||||
|
.tjtp { |
||||
|
width: 331rpx; |
||||
|
height: 90rpx; |
||||
|
/* 自动布局 */ |
||||
|
display: flex; |
||||
|
box-sizing: border-box; |
||||
|
justify-content: center; |
||||
|
padding: 24rpx 0rpx; |
||||
|
gap: 0rpx 20rpx; |
||||
|
flex-wrap: wrap; |
||||
|
border-radius: 8rpx; |
||||
|
background: #2563eb; |
||||
|
font-family: Roboto; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 500; |
||||
|
line-height: 42rpx; |
||||
|
text-align: center; |
||||
|
letter-spacing: normal; |
||||
|
color: #ffffff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.address-items { |
||||
|
padding: 20rpx 15rpx 32rpx 28rpx; |
||||
|
background-color: #fff; |
||||
|
border-bottom: 2rpx solid #f5f5f5; |
||||
|
|
||||
|
.left { |
||||
|
flex: 1; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
.name { |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 700; |
||||
|
color: #101010; |
||||
|
line-height: 40rpx; |
||||
|
margin-right: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.isdefault { |
||||
|
font-size: 20rpx; |
||||
|
font-weight: 400; |
||||
|
color: #fff; |
||||
|
padding: 4rpx 12rpx; |
||||
|
border-radius: 8rpx; |
||||
|
background: linear-gradient(90deg, #4778ff 0%, #4778ffb8 100%); |
||||
|
} |
||||
|
|
||||
|
.info { |
||||
|
width: 100%; |
||||
|
color: #666; |
||||
|
font-size: 24rpx; |
||||
|
font-weight: 400; |
||||
|
margin-top: 12rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.right { |
||||
|
width: 140rpx; |
||||
|
padding-left: 32rpx; |
||||
|
font-size: 24rpx; |
||||
|
font-weight: 400; |
||||
|
color: #4979ff; |
||||
|
text-align: right; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.buts { |
||||
|
width: 100%; |
||||
|
height: 10vh; |
||||
|
background-color: F3F4F6; |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
border-top: 2rpx solid #ebebec; |
||||
|
} |
||||
|
} |
||||
|
</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: 94 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 893 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 521 B |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 288 B |
|
After Width: | Height: | Size: 285 B |
|
After Width: | Height: | Size: 303 B |
|
After Width: | Height: | Size: 296 B |
|
After Width: | Height: | Size: 294 B |
|
After Width: | Height: | Size: 291 B |
|
After Width: | Height: | Size: 365 B |
|
After Width: | Height: | Size: 358 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 296 B |
|
After Width: | Height: | Size: 541 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,92 @@ |
|||||
|
// 定义组合式API仓库
|
||||
|
import { defineStore } from 'pinia' |
||||
|
import { getPrefixName } from '@/config' |
||||
|
|
||||
|
interface userInfoStoreInt { |
||||
|
[n: string]: any |
||||
|
} |
||||
|
export default defineStore( |
||||
|
getPrefixName('user'), |
||||
|
() => { |
||||
|
const token = ref('') |
||||
|
const isShowPrize = ref(false) |
||||
|
const useType = ref<useType>('client') |
||||
|
const userInfo = ref<userInfoStoreInt>({}) |
||||
|
const accountInfo = reactive({ |
||||
|
can_switch: false, |
||||
|
client: { |
||||
|
account: '', |
||||
|
password: '' |
||||
|
}, |
||||
|
agent: { |
||||
|
account: '', |
||||
|
password: '' |
||||
|
} |
||||
|
}) |
||||
|
const bankCard = ref<userInfoStoreInt>({}) |
||||
|
|
||||
|
const checkLogin = computed(() => token.value !== '') |
||||
|
|
||||
|
function logOut() { |
||||
|
token.value = '' |
||||
|
|
||||
|
if (useType.value === 'client') { |
||||
|
accountInfo.client = { account: '', password: '' } |
||||
|
} else { |
||||
|
accountInfo.agent = { account: '', password: '' } |
||||
|
} |
||||
|
useType.value = 'client' |
||||
|
|
||||
|
userInfo.value = {} |
||||
|
bankCard.value = {} |
||||
|
uni.clearStorageSync() |
||||
|
|
||||
|
uni.showToast({ |
||||
|
icon: 'none', |
||||
|
title: '退出成功', |
||||
|
mask: true, |
||||
|
success() { |
||||
|
setTimeout(() => uni.reLaunch({ url: 'pages/login/login' }), 1000) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
token, |
||||
|
accountInfo, |
||||
|
isShowPrize, |
||||
|
useType, |
||||
|
userInfo, |
||||
|
bankCard, |
||||
|
checkLogin, |
||||
|
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,119 @@ |
|||||
|
@import 'uview-plus/theme.scss'; |
||||
|
// @use '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,45 @@ |
|||||
|
/** |
||||
|
* 获取用户头像地址 |
||||
|
* @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}` |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
import useUserStore from '../store/user' |
||||
|
|
||||
|
interface ResponseOptions { |
||||
|
url: string |
||||
|
headers?: { [key: string]: string } |
||||
|
method?: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT' |
||||
|
data?: { [key: string]: any } |
||||
|
isSinglePost?: boolean |
||||
|
} |
||||
|
|
||||
|
const userStore = useUserStore() |
||||
|
|
||||
|
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
|
||||
|
|
||||
|
const header = Object.assign({ 'content-type': 'application/json', Authorization: '' }, headers) |
||||
|
|
||||
|
if (userStore.token) { |
||||
|
header['Authorization'] = 'Bearer' + userStore.token |
||||
|
} |
||||
|
|
||||
|
uni.request({ |
||||
|
url, |
||||
|
header, |
||||
|
method, |
||||
|
data, |
||||
|
success(res) { |
||||
|
const data = res.data as { code: number; data: object; msg: string } |
||||
|
switch (data.code) { |
||||
|
case 1005: |
||||
|
uni.showToast({ title: '登录状态已失效,请重新登录!', icon: 'none' }) |
||||
|
setTimeout(() => uni.navigateTo({ url: 'pages/login/login' }), 1000) |
||||
|
break |
||||
|
case 200: |
||||
|
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.controller = null |
||||
|
_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), '') |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}) |
||||