diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..4ed7ec7 --- /dev/null +++ b/.env.development @@ -0,0 +1,5 @@ +ENV='development' +# base api +VITE_APP_BASE_URL = 'https://evote.truescloud.com' +VITE_APP_BASE_PRE = '/dev-api' +VITE_APP_BASE_NAME = 'POS' diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..6ca60a8 --- /dev/null +++ b/.env.production @@ -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' + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0ea3957 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +dist +node_modules +uni_modules diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..f44624e --- /dev/null +++ b/.eslintrc.cjs @@ -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, // 防止 + +`; + 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); \ No newline at end of file diff --git a/auto/preinstall.js b/auto/preinstall.js new file mode 100644 index 0000000..01f63a5 --- /dev/null +++ b/auto/preinstall.js @@ -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) +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..b05e747 --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..350e978 --- /dev/null +++ b/package.json @@ -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" + } +} \ No newline at end of file diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..b95142e --- /dev/null +++ b/src/App.vue @@ -0,0 +1,29 @@ + + + + diff --git a/src/api/common.ts b/src/api/common.ts new file mode 100644 index 0000000..af0397f --- /dev/null +++ b/src/api/common.ts @@ -0,0 +1,25 @@ +import { request } from '@/utils/http' + +export function getVoteList(data: pageType) { + return request.http({ + url: '/api/vote_list', + method: 'GET', + data + }) +} + +export function getVoteDetail(data: { id: number }) { + return request.http({ + url: '/api/vote_result_detail', + method: 'GET', + data + }) +} + +export function getVoteResult(data: pageType) { + return request.http({ + url: '/api/vote_result', + method: 'GET', + data + }) +} diff --git a/src/api/login.ts b/src/api/login.ts new file mode 100644 index 0000000..a98c560 --- /dev/null +++ b/src/api/login.ts @@ -0,0 +1,39 @@ +import { request } from '@/utils/http' + +export function getOpenid(data: { code: string }) { + return request.http({ + url: '/api/openid', + data + }) +} + +export function getMobile(data: { code: string; openid: string }) { + return request.http({ + url: '/api/mobile', + data + }) +} + +export function getAdminPhone() { + return request.http({ + url: '/api/admin_mobile', + method: 'GET' + }) +} +//用户签到 +export function getSign(data: { meetId: string; openid: string }) { + return request.http({ + url: '/api/sign', + method: 'GET', + data + }) +} + +//扫码时手机号获取用户信息 +export function getmemberMobileGet(data: { meetId: string; openid: string; mobile: string }) { + return request.http({ + url: '/api/member_mobile_get', + method: 'GET', + data + }) +} \ No newline at end of file diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..81ce8ce --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,61 @@ +import { request } from '@/utils/http' + +export interface listType { + name: string + age: number + sex: number + nation: string + mobile: string + position: string + work_unit: string +} + +export interface dateListtype extends listType { + id: number +} + +export function infoForOpenid(data: { openid: string; mobile: string ; meetId: string }) { + return request.http({ + url: '/api/member_mobile_get', + method: 'GET', + data + }) +} + +// 手机号获取用户信息 +export function getMember_mobile(data: any) { + return request.http({ + url: '/api/member_mobile', + method: 'GET', + data + }) +} + +export function list(data: { name: string, meetId: string }) { + return request.http({ + url: '/api/member_name', + method: 'GET', + data + }) +} + +export function update(data: { [n: string]: string }, openid: string) { + return request.http({ + url: '/api/member_update', + data: Object.assign(data, { openid }) + }) +} + +export function bind(data: { id: number; openid: string }) { + return request.http({ + url: '/api/name_sub', + data + }) +} + +export function add(data: listType) { + return request.http({ + url: '/api/member_add', + data + }) +} diff --git a/src/api/votingElection.ts b/src/api/votingElection.ts new file mode 100644 index 0000000..9fb86e6 --- /dev/null +++ b/src/api/votingElection.ts @@ -0,0 +1,44 @@ +import { request } from '@/utils/http' + +// 获取投票选举(正在进行) +export function getVoteprogress(id: string) { + return request.http({ + url: '/api/vote_progress?meetId='+ id, + method: 'GET' + }) +} + +//用户投票 +export function voteMember(data: any) { + return request.http({ + url: '/api/vote_member', + data + }) +} + +// 获取我的选举 +export function getMyvote(data: any) { + return request.http({ + url: '/api/my_vote', + method: 'GET', + data + }) +} + +// 手机号获取用户信息 +export function getMember_mobile(data: any) { + return request.http({ + url: '/api/member_mobile', + method: 'GET', + data + }) +} + +// 判断用户是否签到 +export function getIs_sign(data: any) { + return request.http({ + url: '/api/is_sign', + method: 'GET', + data + }) +} diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..3b11541 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,13 @@ +export const Prefix = 'Election_' + +export const getPrefixName = (name: string) => { + return Prefix + name +} + +export function getAuthorization() { + return uni.getStorageSync(getPrefixName('user')) +} + +export function removeAuthorization() { + return uni.removeStorageSync(getPrefixName('user')) +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..8d202a8 --- /dev/null +++ b/src/main.ts @@ -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 } +} diff --git a/src/manifest.json b/src/manifest.json new file mode 100644 index 0000000..39cca9f --- /dev/null +++ b/src/manifest.json @@ -0,0 +1,131 @@ +{ + "name" : "惠企通", + "appid" : "__UNI__4CC99EE", + "description" : "v3+ts+uniapp模版", + "versionName" : "1.0.68", + "versionCode" : 168, + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "compatible" : { + "ignoreVersion" : true + }, + /* 模块配置 */ + "modules" : { + "Barcode" : {}, + "Camera" : {}, + "VideoPlayer" : {}, + "Share" : {}, + "Geolocation" : {}, + "Maps" : {} + }, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "minSdkVersion" : 21 + }, + /* ios打包配置 */ + "ios" : { + "dSYMs" : false + }, + /* SDK配置 */ + "sdkConfigs" : { + "ad" : {}, + "share" : { + "weixin" : { + "appid" : "wx5d1a07b75bd48225", + "UniversalLinks" : "" + } + }, + "geolocation" : { + "amap" : { + "name" : "amap_18648278829CcsBXVUm1", + "__platform__" : [ "ios", "android" ], + "appkey_ios" : "37180416cb95db05dc9639e616655a7a", + "appkey_android" : "37180416cb95db05dc9639e616655a7a" + } + }, + "maps" : { + "amap" : { + "name" : "amap_18648278829CcsBXVUm1", + "appkey_ios" : "37180416cb95db05dc9639e616655a7a", + "appkey_android" : "37180416cb95db05dc9639e616655a7a" + } + } + }, + "icons" : { + "android" : { + "hdpi" : "src/static/logo.png", + "xhdpi" : "src/static/logo.png", + "xxhdpi" : "src/static/logo.png", + "xxxhdpi" : "src/static/logo.png" + } + }, + "splashscreen" : { + "iosStyle" : "common", + "androidStyle" : "default", + "android" : { + "hdpi" : "", + "xhdpi" : "", + "xxhdpi" : "" + }, + "ios" : { + "storyboard" : "C:/Users/Lenovo/Desktop/CustomStoryboard.zip" + } + } + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "wx4f9dae5cc37dd9f4", + "setting" : { + "urlCheck" : false, + "es6" : true, + "postcss" : false, + "minified" : true + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "3" +} diff --git a/src/pages.json b/src/pages.json new file mode 100644 index 0000000..d6905dc --- /dev/null +++ b/src/pages.json @@ -0,0 +1,85 @@ +{ + "easycom": { + "autoscan": true, + "custom": { + "^ex-(.*)": "feng-uniapp-exploit/components/ex-$1/ex-$1.vue", + "^u-(.*)": "uview-plus/components/u-$1/u-$1.vue" + } + }, + "pages": [ + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "首页", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/memberCenter/index", + "style": { + "navigationBarTitleText": "会员中心", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/learningCenter/index", + "style": { + "navigationBarTitleText": "学习中心", + "enablePullDownRefresh": true + } + }, + { + "name": "user", + "path": "pages/mine/index", + "style": { + "navigationBarTitleText": "个人中心", + "enablePullDownRefresh": true + } + }, + { + "path": "pages/login/login", + "style": { + "navigationBarTitleText": "登录", + "enablePullDownRefresh": false, + "navigationStyle": "custom" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "white", + "navigationBarBackgroundColor": "#F1F3F9", + "backgroundColor": "#F8F8F8" + }, + "tabBar": { + "color": "#9CA3AF", + "selectedColor": "#2563EB", + "borderStyle": "white", + "backgroundColor": "#FFFFFF", + "list": [ + { + "pagePath": "pages/index/index", + "iconPath": "static/tabbar/index.png", + "selectedIconPath": "static/tabbar/index_select.png", + "text": "首页" + }, + { + "pagePath": "pages/memberCenter/index", + "iconPath": "static/tabbar/hyzx.png", + "selectedIconPath": "static/tabbar/hyzx_select.png", + "text": "会员中心" + }, + { + "pagePath": "pages/learningCenter/index", + "iconPath": "static/tabbar/xxzx.png", + "selectedIconPath": "static/tabbar/xxzx_select.png", + "text": "学习中心" + }, + { + "pagePath": "pages/mine/index", + "iconPath": "static/tabbar/grzx.png", + "selectedIconPath": "static/tabbar/grzx_select.png", + "text": "个人中心" + } + ] + } +} \ No newline at end of file diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue new file mode 100644 index 0000000..49dda52 --- /dev/null +++ b/src/pages/index/index.vue @@ -0,0 +1,283 @@ + + + + + diff --git a/src/pages/learningCenter/index.vue b/src/pages/learningCenter/index.vue new file mode 100644 index 0000000..90d1b5f --- /dev/null +++ b/src/pages/learningCenter/index.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/pages/login/login.vue b/src/pages/login/login.vue new file mode 100644 index 0000000..36861da --- /dev/null +++ b/src/pages/login/login.vue @@ -0,0 +1,111 @@ + + + + \ No newline at end of file diff --git a/src/pages/memberCenter/index.vue b/src/pages/memberCenter/index.vue new file mode 100644 index 0000000..0539b63 --- /dev/null +++ b/src/pages/memberCenter/index.vue @@ -0,0 +1,203 @@ + + + + + diff --git a/src/pages/mine/index.vue b/src/pages/mine/index.vue new file mode 100644 index 0000000..6228e2f --- /dev/null +++ b/src/pages/mine/index.vue @@ -0,0 +1,331 @@ + + + + diff --git a/src/permission.ts b/src/permission.ts new file mode 100644 index 0000000..ec90164 --- /dev/null +++ b/src/permission.ts @@ -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) + } + }) + }) +} diff --git a/src/share.vue b/src/share.vue new file mode 100644 index 0000000..49c7feb --- /dev/null +++ b/src/share.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/src/static/img/Group.png b/src/static/img/Group.png new file mode 100644 index 0000000..848be8c Binary files /dev/null and b/src/static/img/Group.png differ diff --git a/src/static/logo.png b/src/static/logo.png new file mode 100644 index 0000000..ff95dd9 Binary files /dev/null and b/src/static/logo.png differ diff --git a/src/static/tabbar/grzx.png b/src/static/tabbar/grzx.png new file mode 100644 index 0000000..289bcb6 Binary files /dev/null and b/src/static/tabbar/grzx.png differ diff --git a/src/static/tabbar/grzx_select.png b/src/static/tabbar/grzx_select.png new file mode 100644 index 0000000..87b1bbc Binary files /dev/null and b/src/static/tabbar/grzx_select.png differ diff --git a/src/static/tabbar/hyzx.png b/src/static/tabbar/hyzx.png new file mode 100644 index 0000000..9630955 Binary files /dev/null and b/src/static/tabbar/hyzx.png differ diff --git a/src/static/tabbar/hyzx_select.png b/src/static/tabbar/hyzx_select.png new file mode 100644 index 0000000..962ae14 Binary files /dev/null and b/src/static/tabbar/hyzx_select.png differ diff --git a/src/static/tabbar/index.png b/src/static/tabbar/index.png new file mode 100644 index 0000000..aa088d6 Binary files /dev/null and b/src/static/tabbar/index.png differ diff --git a/src/static/tabbar/index_select.png b/src/static/tabbar/index_select.png new file mode 100644 index 0000000..71421fa Binary files /dev/null and b/src/static/tabbar/index_select.png differ diff --git a/src/static/tabbar/xxzx.png b/src/static/tabbar/xxzx.png new file mode 100644 index 0000000..9efa204 Binary files /dev/null and b/src/static/tabbar/xxzx.png differ diff --git a/src/static/tabbar/xxzx_select.png b/src/static/tabbar/xxzx_select.png new file mode 100644 index 0000000..c3ba4f4 Binary files /dev/null and b/src/static/tabbar/xxzx_select.png differ diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..86da23d --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,10 @@ +import { createPinia } from 'pinia' +import { createUnistorage } from 'pinia-plugin-unistorage' + +const store = createPinia() +// 使用该插件 +// 关键代码 👇 +store.use(createUnistorage()) + +//导出 +export default store diff --git a/src/store/user.ts b/src/store/user.ts new file mode 100644 index 0000000..cafcc51 --- /dev/null +++ b/src/store/user.ts @@ -0,0 +1,115 @@ +// 定义组合式API仓库 +import { defineStore } from 'pinia' +import { getPrefixName } from '@/config' +import { getOpenid } from '@/api/login' +import { infoForOpenid, bind as bindApi } from '@/api/user' + +interface userInfoStoreInt { + [n: string]: any +} +export default defineStore( + getPrefixName('user'), + () => { + const openId = ref('') + const mobile = ref('') + const meetId = ref('') + const showtoast = ref(false) + const userInfo = ref({}) + + function getopenid(params: { code: string }) { + return new Promise((resolve, reject) => { + getOpenid(params) + .then((res) => { + const { data } = res as { data: string } + + openId.value = data + + resolve({ code: 1, message: '登录成功~' }) + }) + .catch((err) => { + reject(err) + }) + }) + } + + function getUserInfo() { + return new Promise( (resolve, reject) => { + infoForOpenid({ openid: openId.value, mobile: mobile.value, meetId: meetId.value}) + .then((res) => { + const { data } = res as { data: userInfoStoreInt } + userInfo.value = data || {} + resolve({ code: 1, data, message: 'SUCCESS' }) + }) + .catch((err) => { + reject(err) + }) + + }) + } + + function bindUser(id: number) { + return new Promise((resolve, reject) => { + bindApi({ id, openid: openId.value }) + .then(() => { + resolve({ code: 1, message: 'SUCCESS' }) + }) + .catch((err) => { + reject(err) + }) + }) + } + + function logOut() { + userInfo.value = {} + uni.clearStorageSync() + + uni.showToast({ + icon: 'none', + title: '退出成功', + mask: true, + success() { + setTimeout(() => uni.reLaunch({ url: 'pages/login/login' }), 1000) + } + }) + } + + return { + openId, + mobile, + meetId, + showtoast, + userInfo, + getopenid, + bindUser, + getUserInfo, + logOut + } + }, + { + unistorage: { + serializer: { + // 序列化,默认为 JSON.stringify + serialize(v) { + return JSON.stringify(v) + }, + // 反序列化,默认为 JSON.parse + deserialize(v) { + return JSON.parse(v) + } + } + } // 开启后对 state 的数据读写都将持久化 + // unistorage: { + // key: 'userInfo', // 缓存的键,默认为该 store 的 id,这里是 main, + // paths: ['userInfo.token'], // 需要缓存的路径,这里设置 foo 和 nested 下的 data 会被缓存 + // // 初始化恢复前触发 + // beforeRestore(ctx: any) { + // console.log(ctx) + // }, + // // 初始化恢复后触发 + // afterRestore(ctx: any) { + // console.log('ctx', ctx) + // }, + + // }, + } +) diff --git a/src/types/auto-imports.d.ts b/src/types/auto-imports.d.ts new file mode 100644 index 0000000..898474f --- /dev/null +++ b/src/types/auto-imports.d.ts @@ -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 + readonly computed: UnwrapRef + readonly createApp: UnwrapRef + readonly customRef: UnwrapRef + readonly defineAsyncComponent: UnwrapRef + readonly defineComponent: UnwrapRef + readonly effectScope: UnwrapRef + readonly getCurrentInstance: UnwrapRef + readonly getCurrentScope: UnwrapRef + readonly h: UnwrapRef + readonly inject: UnwrapRef + readonly isProxy: UnwrapRef + readonly isReactive: UnwrapRef + readonly isReadonly: UnwrapRef + readonly isRef: UnwrapRef + readonly markRaw: UnwrapRef + readonly nextTick: UnwrapRef + readonly onActivated: UnwrapRef + readonly onAddToFavorites: UnwrapRef + readonly onBackPress: UnwrapRef + readonly onBeforeMount: UnwrapRef + readonly onBeforeUnmount: UnwrapRef + readonly onBeforeUpdate: UnwrapRef + readonly onDeactivated: UnwrapRef + readonly onError: UnwrapRef + readonly onErrorCaptured: UnwrapRef + readonly onHide: UnwrapRef + readonly onLaunch: UnwrapRef + readonly onLoad: UnwrapRef + readonly onMounted: UnwrapRef + readonly onNavigationBarButtonTap: UnwrapRef + readonly onNavigationBarSearchInputChanged: UnwrapRef + readonly onNavigationBarSearchInputClicked: UnwrapRef + readonly onNavigationBarSearchInputConfirmed: UnwrapRef + readonly onNavigationBarSearchInputFocusChanged: UnwrapRef + readonly onPageNotFound: UnwrapRef + readonly onPageScroll: UnwrapRef + readonly onPullDownRefresh: UnwrapRef + readonly onReachBottom: UnwrapRef + readonly onReady: UnwrapRef + readonly onRenderTracked: UnwrapRef + readonly onRenderTriggered: UnwrapRef + readonly onResize: UnwrapRef + readonly onScopeDispose: UnwrapRef + readonly onServerPrefetch: UnwrapRef + readonly onShareAppMessage: UnwrapRef + readonly onShareTimeline: UnwrapRef + readonly onShow: UnwrapRef + readonly onTabItemTap: UnwrapRef + readonly onThemeChange: UnwrapRef + readonly onUnhandledRejection: UnwrapRef + readonly onUnload: UnwrapRef + readonly onUnmounted: UnwrapRef + readonly onUpdated: UnwrapRef + readonly onWatcherCleanup: UnwrapRef + readonly provide: UnwrapRef + readonly reactive: UnwrapRef + readonly readonly: UnwrapRef + readonly ref: UnwrapRef + readonly resolveComponent: UnwrapRef + readonly shallowReactive: UnwrapRef + readonly shallowReadonly: UnwrapRef + readonly shallowRef: UnwrapRef + readonly toRaw: UnwrapRef + readonly toRef: UnwrapRef + readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef + readonly triggerRef: UnwrapRef + readonly unref: UnwrapRef + readonly useAttrs: UnwrapRef + readonly useCssModule: UnwrapRef + readonly useCssVars: UnwrapRef + readonly useId: UnwrapRef + readonly useModel: UnwrapRef + readonly useSlots: UnwrapRef + readonly useTemplateRef: UnwrapRef + readonly watch: UnwrapRef + readonly watchEffect: UnwrapRef + readonly watchPostEffect: UnwrapRef + readonly watchSyncEffect: UnwrapRef + } +} diff --git a/src/types/env.d.ts b/src/types/env.d.ts new file mode 100644 index 0000000..7583e5f --- /dev/null +++ b/src/types/env.d.ts @@ -0,0 +1,13 @@ +/// +/// +/// +/// + +declare module '*.vue' { + import { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} + +declare module 'uview-plus' +declare module 'feng-uniapp-exploit' diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 0000000..e85aac8 --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,29 @@ +/* eslint-disable prettier/prettier */ + +declare global { + type useType = 'client' | 'agent' + + /** + * 公共的路径 + * @author shenname + * @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 { } diff --git a/src/uni.scss b/src/uni.scss new file mode 100644 index 0000000..0268b9f --- /dev/null +++ b/src/uni.scss @@ -0,0 +1,118 @@ +@import 'uview-plus/theme.scss'; + +#app { + box-sizing: border-box; + background-color: #f5f5f5 +} + +/* 颜色变量 */ + +/*============================= 文字尺寸 =============================*/ +$font-size-20: 20rpx; +$font-size-22: 22rpx; +$font-size-24: 24rpx; +$font-size-26: 26rpx; +$font-size-28: 28rpx; +$font-size-30: 30rpx; +$font-size-32: 32rpx; +$font-size-34: 34rpx; +$font-size-36: 36rpx; +$font-size-40: 40rpx; + +image { + width: 100%; + height: 100%; + box-sizing: border-box; +} + +view { + box-sizing: border-box; +} + +/*============================= 弹性盒子 =============================*/ +%flex-base { + display: flex; + flex-wrap: nowrap; +} + +$flex-way: ( + start, + flex-start), + (center, center), + (end, flex-end), + (between, space-between), + (around, space-around), + (evenly, space-evenly +); + +@mixin flex-algin($align) { + @each $way, $justify in $flex-way { + &-#{$way} { + @if $way !=$align { + @if $way !=$align { + @extend %flex-base; + align-items: $align; + justify-content: $justify; + } + } + } + } +} + +.flex { + @extend %flex-base; + align-items: center; + justify-content: center; + + @each $way, $justify in (start, flex-start), (center, center), (end, flex-end) { + &-#{$way} { + @include flex-algin($justify); + } + } +} + +[class*="flex-"], +[class^="flex"] { + &.nowrap { + flex-wrap: nowrap; + } + + &.stretch { + align-items: stretch; + } + + @each $direction, $name in (row, direction), (column, direction), (wrap, wrap) { + &.#{$direction} { + flex-#{$name}: $direction; + + &-reverse { + flex-#{$name}: '#{$direction}-reverse'; + } + } + } +} + +@for $i from 1 through 4 { + .flex#{$i} { + flex: $i; + } +} + +/*============================= 文字溢出 =============================*/ +.text-ellipsis { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + @for $i from 2 through 4 { + &-#{$i} { + overflow: hidden; + white-space: normal; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + line-clamp: 1; + -webkit-line-clamp: $i; + } + } +} \ No newline at end of file diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 0000000..a0e0a09 --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1,58 @@ +/** + * 获取用户头像地址 + * @author shenname + * @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 + * @license MIT + * @param { string } url 图片地址 + * @returns { string } + */ +export const getImageUrl = (url?: string) => { + return import.meta.env.VITE_APP_BASE_URL + url +} + +/** + * 获取文件相对路径、URL + * @author shenname + * @license MIT + * @param { string } fileName 文件名称 | 相对路径 + * @param { string } [filePath=images] filePath 文件在 /static 下的路径 获取URL时不传 + * @example + * imgUrl('a.png') + * imgUrl('a.png', '/public/') + * imgUrl('/upload/images/img.png') + * @returns {string} + */ +export const fileUrl = (fileName: string, filePath: string = 'images'): string => { + if (/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/.test(fileName)) { + return import.meta.env.VITE_APP_BASE_URL + fileName + } else { + return `http://cdn-pos.lingji.vip/static/${filePath}/${fileName}` + } +} + +/** + * 判断对象是否为空 + * @author shenname + * @license MIT + * @param any + * @returns {boolean} + */ +export const isEmptyObject = (obj: any): boolean => { + if (obj == null) return true + if (typeof obj !== 'object' || Array.isArray(obj)) return true + return Reflect.ownKeys(obj).length === 0 +} diff --git a/src/utils/http.ts b/src/utils/http.ts new file mode 100644 index 0000000..20a5692 --- /dev/null +++ b/src/utils/http.ts @@ -0,0 +1,61 @@ +interface ResponseOptions { + url: string + headers?: { [key: string]: string } + method?: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT' + data?: { [key: string]: any } + isSinglePost?: boolean +} + +export const request = { + isLock: false, + http({ url = '', headers = {}, data = {}, method = 'POST', isSinglePost = false }: ResponseOptions) { + const _this = this + + return new Promise(function (resolve, reject) { + if (isSinglePost && _this.isLock) { + reject({ message: '加载中' }) + } + _this.isLock = true + + // #ifdef APP-PLUS + url = import.meta.env.VITE_APP_BASE_URL + url + // #endif + // #ifdef H5 + url = import.meta.env.VITE_APP_BASE_PRE + url + // #endif + + // #ifdef MP-WEIXIN + url = import.meta.env.VITE_APP_BASE_URL + url + // #endif + + const header = Object.assign({ 'content-type': 'application/json', Authorization: '' }, headers) + + uni.request({ + url, + header, + method, + data, + success(res) { + const data = res.data as { code: number; data: object; msg: string } + + switch (data.code) { + case 1: + resolve(res.data) + break + default: + uni.showToast({ title: data.msg, icon: 'none', mask: true }) + reject(res.data) + break + } + }, + fail(err) { + uni.showToast({ title: '网络错误', icon: 'none' }) + reject(err) + }, + complete() { + _this.isLock = false + } + }) + }) + } +} diff --git a/src/utils/rules.ts b/src/utils/rules.ts new file mode 100644 index 0000000..f63dd6f --- /dev/null +++ b/src/utils/rules.ts @@ -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) +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..41eaa5b --- /dev/null +++ b/tsconfig.json @@ -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" + ] +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..66a94eb --- /dev/null +++ b/vite.config.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), '') + } + } + } + } +})