@ -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), '') |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}) |
|||