feat:first commit

This commit is contained in:
pengguangxia 2024-08-16 14:04:26 +08:00
commit f276677d09
72 changed files with 33361 additions and 0 deletions

25
.editorconfig Normal file
View File

@ -0,0 +1,25 @@
# .editorconfig
# http://editorconfig.org
# https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties
# 根目录的配置文件,编辑器会由当前目录向上查找,如果找到 `roor = true` 的文件,则不再查找
root = true
# 匹配所有的文件
[*.{js,jsx,ts,tsx,vue,css,scss,md,html,json}]
# 缩进风格space
indent_style = space
# 缩进大小 2
indent_size = 2
# 换行符 lf
end_of_line = lf
# 字符集 utf-8
charset = utf-8
# 不保留行末的空格
trim_trailing_whitespace = true
# 文件末尾添加一个空行
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

12
.env.development Normal file
View File

@ -0,0 +1,12 @@
# just a flag
ENV = 'development'
VUE_APP_STORAGE_PREFIX = 'DOCTOR'
# base api
#VUE_APP_BASE_API = 'https://52ya-test.jcmed.com/doctor'
VUE_APP_BASE_API = 'https://test.jzcscw.cn/dentistry/doctor'
VUE_APP_PUBLIC_PATH = '/'
VUE_APP_PUBLIC_PATH_URL = 'https://52ya-test.jcmed.com/public/upload/'
# VUE_APP_PUBLIC_PATH_URL = 'https://52ya-test.jcmed.com/public/upload/'

11
.env.production Normal file
View File

@ -0,0 +1,11 @@
# just a flag
ENV = 'production'
VUE_APP_STORAGE_PREFIX = 'DOCTOR'
# base api
VUE_APP_BASE_API = 'https://52ya-test.jcmed.com/doctor/'
#VUE_APP_BASE_API = 'https://test.jzcscw.cn/dentistry/doctor'
VUE_APP_PUBLIC_PATH = '/'
VUE_APP_PUBLIC_PATH_URL = 'https://52ya-test.jcmed.com/public/upload/'

10
.eslintignore Normal file
View File

@ -0,0 +1,10 @@
*.min.js
typings
node_modules/
src/utils/
.idea/
.vscode/
.hbuilderx/
dist/
doc/
src/i18n

115
.eslintrc.js Normal file
View File

@ -0,0 +1,115 @@
module.exports = {
root: true,
parser: 'vue-eslint-parser',
env: {
es6: true,
browser: true,
node: true
},
extends: ['alloy', 'prettier'],
plugins: ['prettier'],
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-undef': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-unused-vars': 1, // 不能有声明后未被使用的变量或参数
'no-irregular-whitespace': 2, // 不能有不规则的空格
'no-param-reassign': 0,
'arrow-spacing': [
2,
{
before: true,
after: true
}
], // 要求箭头函数的箭头之前或之后有空格
eqeqeq: [1, 'always', { null: 'ignore' }], // 要求使用 === 和 !==
indent: ['error', 2, { SwitchCase: 1 }],
'keyword-spacing': [
2,
{
before: true,
after: true
}
],
'brace-style': [
2,
'1tbs',
{
allowSingleLine: true
}
], // 大括号风格要求
camelcase: [
1,
{
properties: 'always'
}
], // 要求使用骆驼拼写法
'comma-dangle': [2, 'never'], // 要求或禁止使用拖尾逗号
'comma-spacing': [
2,
{
before: false,
after: true
}
], // 强制在逗号周围使用空格
'comma-style': [2, 'last'], // 逗号风格 要求逗号放在数组元素、对象属性或变量声明之后,且在同一行
'new-parens': 2, // 要求调用无参构造函数时带括号
quotes: [
2,
'single',
{
avoidEscape: true,
allowTemplateLiterals: true
}
], // 强制使用一致的反勾号、双引号或单引号 double:双引号 single:单引号 backtick:反勾号
'semi-spacing': [
2,
{
before: false,
after: true
}
], // 分号前后空格
'space-infix-ops': 2, // 中缀操作符周围要不要有空格
'space-unary-ops': [
2,
{
words: true,
nonwords: false
}
], // 一元运算符的前/后要不要加空格
'spaced-comment': [
2,
'always',
{
markers: ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}
], // 要求或禁止在注释前有空白
'arrow-parens': [2, 'always'], // 要求箭头函数的参数使用圆括号
'linebreak-style': 1, // 强制使用一致的换行符风格
radix: 0,
'no-var': 2, // 禁用var用let和const代替
'prettier/prettier': [
2,
{
printWidth: 150, // 一行代码的最大字符数
tabWidth: 2, // tab宽度为2空格
useTabs: false, // 是否使用tab来缩进
semi: false, // 结尾是否添加分号
singleQuote: true, // 使用单引号
quoteProps: 'as-needed', // object对象中key值是否加引号 as-needed只有在需求要的情况下加引号consistent是有一个需要引号就统一加preserve是保留用户输入的引号
proseWrap: 'preserve', // 换行方式 默认值。因为使用了一些折行敏感型的渲染器如GitHub comment而按照markdown文本样式进行折行
arrowParens: 'always', // 箭头函数单个参数的情况是否省略括号默认always是总是带括号 avoid省略括号
bracketSpacing: true, // object对象里面的key和value值和括号间的空格 默认true
jsxBracketSameLine: false, // jsx标签多行属性写法时中把'>' 是否单独放一行
endOfLine: 'auto', // endOfLine: "<lf|crlf|cr|auto>" 行尾换行符,默认是lf
htmlWhitespaceSensitivity: 'ignore',
trailingComma: 'none', // 尾部逗号设置es5是尾部逗号兼容es5none就是没有尾部逗号all是指所有可能的情况
jsxSingleQuote: true // 在jsx中使用单引号代替双引号
}
]
}
}

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
.DS_Store
node_modules/
unpackage/
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/
.hbuilderx/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

28
.prettierignore Normal file
View File

@ -0,0 +1,28 @@
*.min.js
/node_modules
/dist
/miniprogram/miniprogram_npm
/miniprogram/utils
/miniprogram/i18n
/typings
# OS
.DS_Store
.idea/
.vscode/
.hbuilderx/
.editorconfig
.npmrc
package-lock.json
yarn.*
# Ignored suffix
*.log
*.md
*.svg
*.png
*ignore
## Built-files
.cache
dist
doc
src/i18n

25
.prettierrc.js Normal file
View File

@ -0,0 +1,25 @@
module.exports = {
printWidth: 150, // 一行代码的最大字符数
tabWidth: 2, // tab宽度为2空格
useTabs: false, // 是否使用tab来缩进
semi: false, // 结尾是否添加分号
singleQuote: true, // 使用单引号
quoteProps: 'as-needed', // object对象中key值是否加引号 as-needed只有在需求要的情况下加引号consistent是有一个需要引号就统一加preserve是保留用户输入的引号
jsxSingleQuote: true, // 在jsx中使用单引号代替双引号
trailingComma: 'none', // 尾部逗号设置es5是尾部逗号兼容es5none就是没有尾部逗号all是指所有可能的情况
bracketSpacing: true, // object对象里面的key和value值和括号间的空格 默认true
jsxBracketSameLine: false, // jsx标签多行属性写法时中把'>' 是否单独放一行
arrowParens: 'always', // 箭头函数单个参数的情况是否省略括号默认always是总是带括号 avoid省略括号
proseWrap: 'preserve', // 换行方式 默认值。因为使用了一些折行敏感型的渲染器如GitHub comment而按照markdown文本样式进行折行
htmlWhitespaceSensitivity: 'ignore', // 根据显示样式决定 html 要不要折行
endOfLine: 'lf', // "<lf|crlf|cr|auto>" 行尾换行符,默认是lf
// Prettier 支持对某些文件扩展名,文件夹和特定文件进行不同的配置
overrides: [
{
files: '.prettierrc',
options: {
parser: 'json'
}
}
]
}

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# ai-Guangzhou
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

77
babel.config.js Normal file
View File

@ -0,0 +1,77 @@
const webpack = require('webpack')
const plugins = []
if (process.env.UNI_OPT_TREESHAKINGNG) {
plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js'))
}
if (
(process.env.UNI_PLATFORM === 'app-plus' && process.env.UNI_USING_V8) ||
(process.env.UNI_PLATFORM === 'h5' && process.env.UNI_H5_BROWSER === 'builtin')
) {
const path = require('path')
const isWin = /^win/.test(process.platform)
const normalizePath = (path) => (isWin ? path.replace(/\\/g, '/') : path)
const input = normalizePath(process.env.UNI_INPUT_DIR)
try {
plugins.push([
require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'),
{
file(file) {
file = normalizePath(file)
if (file.indexOf(input) === 0) {
return path.relative(input, file)
}
return false
}
}
])
} catch (e) {}
}
process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui']
process.UNI_LIBRARIES.forEach((libraryName) => {
plugins.push([
'import',
{
libraryName: libraryName,
customName: (name) => {
return `${libraryName}/lib/${name}/${name}`
}
}
])
})
if (process.env.UNI_PLATFORM !== 'h5') {
plugins.push('@babel/plugin-transform-runtime')
}
const config = {
presets: [
[
'@vue/app',
{
modules: webpack.version[0] > 4 ? 'auto' : 'commonjs',
useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry'
}
]
],
plugins
}
const UNI_H5_TEST = '**/@dcloudio/uni-h5/dist/index.umd.min.js'
if (process.env.NODE_ENV === 'production') {
config.overrides = [
{
test: UNI_H5_TEST,
compact: true
}
]
} else {
config.ignore = [UNI_H5_TEST]
}
module.exports = config

19453
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

89
package.json Normal file
View File

@ -0,0 +1,89 @@
{
"name": "ai-guangzhou",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "npm run dev:h5",
"build": "npm run build:h5",
"build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build",
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
"build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve",
"dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch",
"dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch"
},
"dependencies": {
"@dcloudio/uni-app": "2.0.2-3090820231124001",
"@dcloudio/uni-app-plus": "2.0.2-3090820231124001",
"@dcloudio/uni-h5": "2.0.2-3090820231124001",
"@dcloudio/uni-i18n": "2.0.2-3090820231124001",
"@dcloudio/uni-mp-alipay": "2.0.2-3090820231124001",
"@dcloudio/uni-mp-toutiao": "^2.0.2-4020420240722003",
"@dcloudio/uni-mp-vue": "2.0.2-3090820231124001",
"@dcloudio/uni-mp-weixin": "2.0.2-3090820231124001",
"@dcloudio/uni-stacktracey": "2.0.2-3090820231124001",
"@dcloudio/uni-stat": "2.0.2-3090820231124001",
"@dcloudio/uni-ui": "^1.4.28",
"@types/crypto-js": "^4.1.1",
"@typescript-eslint/parser": "^5.57.0",
"@vue/shared": "^3.0.0",
"babel-eslint": "^10.1.0",
"core-js": "^3.8.3",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.7",
"eslint": "^8.37.0",
"eslint-config-alloy": "^4.9.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-webpack-plugin": "^4.0.1",
"flyio": "^0.6.2",
"js-md5": "^0.7.3",
"uni-read-pages": "^1.0.5",
"uni-simple-router": "^2.0.7",
"vue": ">= 2.6.14 < 2.7",
"vue-class-component": "^6.3.2",
"vue-eslint-parser": "^9.1.1",
"vue-property-decorator": "^8.0.0",
"vuex": "^3.2.0"
},
"devDependencies": {
"@babel/plugin-syntax-typescript": "^7.2.0",
"@dcloudio/types": "^3.3.2",
"@dcloudio/uni-automator": "2.0.2-3090820231124001",
"@dcloudio/uni-cli-i18n": "2.0.2-3090820231124001",
"@dcloudio/uni-cli-shared": "2.0.2-3090820231124001",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-migration": "2.0.2-3090820231124001",
"@dcloudio/uni-template-compiler": "2.0.2-3090820231124001",
"@dcloudio/vue-cli-plugin-hbuilderx": "2.0.2-3090820231124001",
"@dcloudio/vue-cli-plugin-uni": "2.0.2-3090820231124001",
"@dcloudio/vue-cli-plugin-uni-optimize": "2.0.2-3090820231124001",
"@dcloudio/webpack-uni-mp-loader": "2.0.2-3090820231124001",
"@dcloudio/webpack-uni-pages-loader": "2.0.2-3090820231124001",
"@types/uni-app": "^1.4.4",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.8",
"@vue/cli-service": "~5.0.0",
"babel-plugin-import": "^1.11.0",
"cross-env": "^7.0.2",
"jest": "^25.4.0",
"mini-types": "*",
"miniprogram-api-typings": "*",
"postcss-comment": "^2.0.0",
"sass": "^1.60.0",
"sass-loader": "10.1.1",
"typescript": "~4.5.5",
"vue-template-compiler": ">= 2.6.14 < 2.7"
},
"browserslist": [
"Android >= 4.4",
"ios >= 9"
],
"uni-app": {
"scripts": {}
}
}

27
postcss.config.js Normal file
View File

@ -0,0 +1,27 @@
const path = require('path')
const webpack = require('webpack')
const config = {
parser: require('postcss-comment'),
plugins: [
require('postcss-import')({
resolve(id, basedir, importOptions) {
if (id.startsWith('~@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3))
} else if (id.startsWith('@/')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2))
} else if (id.startsWith('/') && !id.startsWith('//')) {
return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1))
}
return id
}
}),
require('autoprefixer')({
remove: process.env.UNI_PLATFORM !== 'h5'
}),
require('@dcloudio/vue-cli-plugin-uni/packages/postcss')
]
}
if (webpack.version[0] > 4) {
delete config.parser
}
module.exports = config

34
public/index.html Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title><%= htmlWebpackPlugin.options.title %></title>
<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>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<style>
html,
body,
page {
width: 100%;
min-height: 100%;
padding-bottom: env(safe-area-inset-bottom);
}
</style>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>
<div id="app"></div>
</body>
</html>

10
shime-uni.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
import Vue from 'vue'
declare module 'vue/types/options' {
type Hooks = App.AppInstance & Page.PageInstance
interface ComponentOptions<V extends Vue> extends Hooks {
/**
*
*/
mpType?: string
}
}

5
shime-vue.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
declare let ROUTES = []

53
src/App.vue Normal file
View File

@ -0,0 +1,53 @@
<script lang="ts">
export default {
mpType: 'app',
onLaunch() {},
onLoad() {},
onShow() {},
onHide() {}
}
</script>
<style lang="scss">
* {
padding: 0;
margin: 0;
box-sizing: border-box;
*::-webkit-scrollbar {
display: none;
}
}
/*每个页面公共css */
.page_class {
width: 100%;
min-height: 100vh;
background-color: #f4f4f4;
display: flex;
flex-direction: column;
}
.rich_text,
uni-rich-text {
word-break: break-all;
ul,
ol,
blockquote,
li {
padding: revert;
margin: revert;
}
table {
border-collapse: collapse;
}
table,
th,
td {
border: 1px solid black;
}
}
</style>

View File

@ -0,0 +1,45 @@
<template>
<view class="cus_button" @click.stop="handleClick" :style="[btnStyle]">{{ buttonText }}</view>
</template>
<script>
export default {
name: 'cusButton',
props: {
propData: {
type: Object,
default: () => ({})
},
highlight: {
type: Boolean,
default: false
},
buttonText: {
type: String,
default: ''
},
btnStyle: {
type: Object,
default: {}
}
},
emits: ['onClick'],
methods: {
handleClick() {
this.$emit('onClick', this.propData)
}
}
}
</script>
<style scoped lang="scss">
@import '@/static/style/public.scss';
.cus_button {
border-radius: 45rpx;
display: flex;
font-family: 'PingFang SC';
color: #1d2129;
align-items: center;
justify-content: center;
}
</style>

View File

@ -0,0 +1,69 @@
<template>
<uni-popup ref="bookingPopup" type="center" :is-mask-click="false" style="z-index: 99999">
<view class="booking_popup">
<view class="tip_box">{{ title }}</view>
<view class="btn_box">
<view class="close" @click="cancel">{{ cancelText }}</view>
<view class="confirm" @click="confirm">{{ confirmText }}</view>
</view>
</view>
</uni-popup>
</template>
<script>
export default {
name: 'doubleConfirm',
props: ['title', 'cancelText', 'confirmText'],
methods: {
confirm() {
this.$emit('confirm')
},
cancel() {
this.$refs.bookingPopup.close()
this.$emit('cancel')
},
show() {
this.$refs.bookingPopup.open()
}
}
}
</script>
<style scoped lang="scss">
.booking_popup {
width: 560rpx;
border-radius: 20rpx;
background: #fff;
box-shadow: 0 0 10rpx 0 #0000001a;
.tip_box {
padding: 50rpx 40rpx;
color: #1d2129;
text-align: center;
font-size: 30rpx;
font-weight: 400;
line-height: 60rpx;
}
.btn_box {
border-top: 1rpx solid #e5e5e5;
font-size: 30rpx;
font-weight: 400;
line-height: 32rpx;
text-align: center;
display: flex;
align-items: center;
view {
width: 50%;
padding: 34rpx 0;
}
.close {
color: #666666;
}
.confirm {
border-top: 1rpx solid #fcbd00;
color: #1d2129;
background: #fcbd00;
border-radius: 0 0 20rpx 0;
}
}
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<view class="info_gender" :style="{ backgroundColor: data.gender === GenderType.boy ? '#6AC7FC' : '#FF9FC2', padding }">
<image v-if="data.gender === GenderType.girl" class="gender_icon" mode="aspectFill" src="@/static/images/common/girl.png" />
<image v-else class="gender_icon" mode="aspectFill" src="@/static/images/common/boy.png" />
<view>{{ data.age || 0 }}</view>
</view>
</template>
<script>
import { GenderType } from '@/enum/indexEnum'
export default {
name: 'genderBox',
computed: {
GenderType() {
return GenderType
}
},
props: {
data: {
type: Object,
default: {}
},
padding: {
type: String,
default: ''
}
}
}
</script>
<style scoped lang="scss">
.info_gender {
display: flex;
padding: 0 8rpx;
align-items: center;
color: white;
font-size: 20rpx;
border-radius: 6rpx;
.gender_icon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
}
</style>

View File

@ -0,0 +1,125 @@
<template>
<view
class="custom-navbar"
:style="{
backgroundColor: backgroundColor,
color: textColor,
position: fixed ? 'fixed' : 'absolute',
paddingTop: `${statusBarHeight}px`,
height: `${navHeight}px`
}"
>
<view class="nav-grid">
<view class="nav-side nav-left" @click="handleLeftClick">
<slot name="left">
<image v-if="showBack" class="arrow-icon" src="/static/images/common/left.png" mdoe="aspectFill" />
</slot>
</view>
<view class="nav-title">
<slot name="title"></slot>
</view>
<view class="nav-side nav-right" @click="handleRightClick">
<slot name="right"></slot>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'navBar',
props: {
showBack: {
type: Boolean,
default: true
},
fixed: {
type: Boolean,
default: true
},
backgroundColor: {
type: String,
default: 'transDOCTOR'
},
textColor: {
type: String,
default: '#000000'
}
},
emits: ['leftClick', 'rightClick'],
data() {
return {
statusBarHeight: 0,
navHeight: 44
}
},
mounted() {
const systemInfo = uni.getSystemInfoSync()
this.statusBarHeight = systemInfo.statusBarHeight
// navHeight
let navHeight = 0
if (systemInfo.platform === 'android') {
navHeight = 48
} else if (systemInfo.platform === 'ios') {
navHeight = 44
} else {
navHeight = 44
}
this.navHeight = this.statusBarHeight + navHeight
this.$store.dispatch('SetNavHeight', this.navHeight)
},
methods: {
handleLeftClick() {
this.$emit('leftClick')
},
handleRightClick() {
this.$emit('rightClick')
}
}
}
</script>
<style scoped lang="scss">
.custom-navbar {
display: flex;
justify-content: center;
top: 0;
left: 0;
width: 100%;
box-sizing: border-box;
z-index: 999;
.nav-grid {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
width: 100%;
padding: 0 30rpx;
.nav-side {
cursor: pointer;
&.nav-left {
text-align: left;
-webkit-tap-highlight-color: transparent;
}
&.nav-right {
display: flex;
justify-content: flex-end;
text-align: right;
}
}
.arrow-icon {
width: 28rpx;
height: 28rpx;
vertical-align: middle;
}
.nav-title {
display: flex;
justify-content: center;
align-items: center;
font-size: 34rpx;
}
}
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<view class="uni-tabbar width_wrapper">
<view class="uni-tabbar__item" v-for="(item, index) in tabBar" :key="index" v-if="item.show" @tap="changeTab(item)">
<view class="uni-tabbar__bd">
<view class="uni-tabbar__icon">
<image v-if="item.pagePath == pagePath" class="icon-img" mode="aspectFit" :src="item.selectedIconPath"></image>
<image v-else class="icon-img" mode="aspectFit" :src="item.iconPath"></image>
</view>
<view class="uni-tabbar__label" :class="{ active: item.pagePath == pagePath }">
{{ item.text }}
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'TabBar',
props: {
pagePath: {
type: String,
required: true,
default: ''
}
},
data() {
return {}
},
computed: {
tabBar() {
return [
{
pagePath: '/pages/index/index',
text: '检查列表',
iconPath: '/static/images/tabBar/home.png',
selectedIconPath: '/static/images/tabBar/home-active.png',
show: true
},
{
pagePath: '/pages/prophylaxis/index',
text: '预防列表',
iconPath: '/static/images/tabBar/prophylaxis.png',
selectedIconPath: '/static/images/tabBar/prophylaxis-active.png',
show: true
},
{
pagePath: '/pages/diagnosis/index',
text: '诊疗列表',
iconPath: '/static/images/tabBar/diagnosis.png',
selectedIconPath: '/static/images/tabBar/diagnosis-active.png',
show: true
},
{
pagePath: '/pages/mine/index',
text: '我的',
iconPath: '/static/images/tabBar/mine.png',
selectedIconPath: '/static/images/tabBar/mine-active.png',
show: true
}
]
}
},
onLoad() {
// TabBar
uni.hideTabBar()
},
methods: {
changeTab(item) {
const currentPagePath = `/${getCurrentPages().pop().route}`
//
if (item.pagePath === currentPagePath) {
return
}
// 使switchTabswitch
uni.switchTab({
url: item.pagePath
})
}
}
}
</script>
<style scoped lang="scss">
.uni-tabbar {
position: fixed;
bottom: 0;
left: 0;
z-index: 999;
width: 100%;
display: flex;
justify-content: space-around;
padding-bottom: env(safe-area-inset-bottom);
box-sizing: initial;
background-color: #fff;
box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(148, 151, 184, 0.08);
.uni-tabbar__item {
flex: 1;
display: block;
height: 120rpx;
font-size: 20rpx;
text-align: center;
}
.uni-tabbar__icon {
margin-top: 15rpx;
height: 24px;
line-height: 24px;
text-align: center;
}
.icon {
display: inline-block;
}
.uni-tabbar__label {
margin-top: 15rpx;
line-height: 24rpx;
font-size: 24rpx;
color: #8d96a1;
&.active {
color: #1d2129;
}
}
.icon-img {
height: 24px;
width: 24px;
}
}
</style>

View File

@ -0,0 +1,511 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{ label + '' }}</span>
<view class="uni-stat-box" :class="{ 'uni-stat__actived': current }">
<view class="uni-select" :class="{ 'uni-select--disabled': disabled }">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{ textShow }}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{ typePlaceholder }}</view>
<view v-if="current && clear && !disabled" @click.stop="clearVal">
<uni-icons type="clear" color="#c0c4cc" size="24" />
</view>
<view v-else>
<uni-icons :type="showSelector ? 'top' : 'bottom'" size="14" color="#999" />
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{ emptyTips }}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item, index) in mixinDatacomResData" :key="index" @click="change(item)">
<text :class="{ 'uni-select__selector__disabled': item.disable }">{{ formatItemName(item) }}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染的下拉框组件
* @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
* @property {String} value 默认值
* @property {Array} localdata 本地数据 格式 [{text:'',value:''}]
* @property {Boolean} clear 是否可以清空已选项
* @property {Boolean} emptyText 没有数据时显示的文字 本地数据无效
* @property {String} label 左侧标题
* @property {String} placeholder 输入框的提示文字
* @property {Boolean} disabled 是否禁用
* @event {Function} change 选中发生变化触发
*/
export default {
name: 'uni-data-select',
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default() {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
// field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
format: {
type: String,
default: ''
}
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: 'uni-data-select-lastSelectedValue'
}
},
created() {
this.debounceGet = this.debounce(() => {
this.query()
}, 300)
if (this.collection && !this.localdata.length) {
this.debounceGet()
}
},
computed: {
typePlaceholder() {
const text = {
'opendb-stat-app-versions': '版本',
'opendb-app-channels': '渠道',
'opendb-app-list': '应用'
}
const common = this.placeholder
const placeholder = text[this.collection]
return placeholder ? common + placeholder : common
},
valueCom() {
// #ifdef VUE3
return this.modelValue
// #endif
// #ifndef VUE3
return this.value
// #endif
},
textShow() {
//
let text = this.current
if (text.length > 10) {
return text.slice(0, 25) + '...'
}
return text
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
}
},
methods: {
debounce(fn, time = 100) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
//
query() {
this.mixinDatacomEasyGet()
},
//
onMixinDatacomPropsChange() {
if (this.collection) {
this.debounceGet()
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find((item) => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false
this.mixinDatacomResData.forEach((item) => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled
},
clearVal() {
this.emit('')
if (this.collection) {
this.removeCache()
}
},
change(item) {
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val)
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let { text, value, channel_code } = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
//
let str = ''
str = this.format
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`, 'g'), item[key])
}
return str
} else {
return this.collection.indexOf('app-list') > 0 ? `${text}(${value})` : text ? text : `未命名${channel_code}`
}
},
//
getLoadData() {
return this.mixinDatacomResData
},
// key
getCurrentCacheKey() {
return this.collection
},
//
getCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {}
return cacheData[name]
},
//
setCache(value, name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {}
cacheData[name] = value
uni.setStorageSync(this.cacheKey, cacheData)
},
//
removeCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {}
delete cacheData[name]
uni.setStorageSync(this.cacheKey, cacheData)
}
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 100%;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
width: 100%;
flex: 1;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 50px;
padding: 25rpx 40rpx;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 35px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 35px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #ffffff;
border: 1px solid #ebeef5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 600px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #ebeef5;
}
.uni-popper__arrow::after {
content: ' ';
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 100%;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: $uni-base-color;
font-size: 28rpx;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
</style>

View File

@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "Pull up to show more",
"uni-load-more.contentrefresh": "loading...",
"uni-load-more.contentnomore": "No more data"
}

View File

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "上拉显示更多",
"uni-load-more.contentrefresh": "正在加载...",
"uni-load-more.contentnomore": "没有更多数据了"
}

View File

@ -0,0 +1,5 @@
{
"uni-load-more.contentdown": "上拉顯示更多",
"uni-load-more.contentrefresh": "正在加載...",
"uni-load-more.contentnomore": "沒有更多數據了"
}

File diff suppressed because one or more lines are too long

0
src/enum/indexEnum.ts Normal file
View File

70
src/main.ts Normal file
View File

@ -0,0 +1,70 @@
import Vue from 'vue'
import App from './App.vue'
import store from './store'
import { router, RouterMount } from './router'
import BaseMixin from '@/mixins/BaseMixin'
import NavBar from '@/components/navBar/index.vue'
import TabBar from '@/components/tabBar/index.vue'
import '@/static/style/public.scss'
Vue.use(router)
Vue.config.productionTip = false
Vue.use(BaseMixin)
Vue.component('nav-bar', NavBar)
Vue.component('tab-bar', TabBar)
Vue.prototype.$store = store
function isPromise(obj: any) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
}
uni.addInterceptor({
returnValue(res: any) {
if (!isPromise(res)) {
return res
}
return new Promise((resolve, reject) => {
res.then((res: [any, any]) => {
if (res[0]) {
reject(res[0])
} else {
resolve(res[1])
}
})
})
}
})
const app: any = new Vue({
store,
...App
})
// #ifdef H5
RouterMount(app, router, '#app')
// #endif
// #ifndef H5
app.$mount() // 为了兼容小程序及app端必须这样写才有效果
// #endif
// #ifdef APP-PLUS
plus.key.addEventListener(
'backbutton',
() => {
let pages = getCurrentPages()
if (pages.length === 1) {
// 首次按键,提示‘再按一次退出应用’
uni.showModal({
title: '提示',
content: '是否退出应用?',
cancelText: '取消',
confirmText: '确定',
success: function (res) {
if (res.confirm) {
// 退出当前应用改方法只在App中生效
plus.runtime.quit()
}
}
})
}
},
false
)
// #endif

87
src/manifest.json Normal file
View File

@ -0,0 +1,87 @@
{
"name": "doctor_mp",
"appid": "__UNI__F3A1F32",
"description": "",
"versionName": "1.0.0",
"versionCode": 100,
"transformPx": false,
"app-plus": {
/* 5+App */
"modules": {
"Barcode": {},
"Camera": {},
"VideoPlayer": {},
"Share": {},
"Payment": {}
},
/* */
"distribute": {
/* */
"android": {
/* android */
"permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios": {},
"sdkConfigs": {}
},
/* SDK */
"usingComponents": true,
"ignoreVersion": true
},
"quickapp": {},
/* */
"h5": {},
"mp-weixin": {
/* */
"appid": "wxa56884e0db8477e5",
"setting": {
"urlCheck": false,
"es6": true,
"postcss": true,
"minified": true
},
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"setting": {
"urlCheck": false,
"es6": true,
"postcss": true,
"minified": true
},
"usingComponents": true
},
"mp-qq": {
"usingComponents": true
}
}

166
src/mixins/BaseMixin.ts Normal file
View File

@ -0,0 +1,166 @@
import { JumpType } from '@/utils/common'
import { dateFormat, formatRichText, PUBLIC_PATH_URL, showToast } from '@/utils/util'
import store from '@/store'
export default {
install(Vue: any) {
Vue.mixin({
data() {
return {}
},
computed: {},
methods: {
getStatusHeightCss() {
const systemInfo = uni.getSystemInfoSync()
return { '--status-height': systemInfo.statusBarHeight + 'px' }
},
getNavHeightCss() {
return store.getters.getNavHeight
},
/**
*
* @param url
* @param jumpType
* @param delay
*/
goto(url: string, jumpType: JumpType = JumpType.navigator, delay: number = 0) {
// console.info('goto', url, jumpType, delay)
let checkIsTab = (url: string): boolean => {
// TODO tab标签
let tabPage = ['/pages/index/index', '/pages/mine/index']
let isTab = false
if (url) {
for (let i = 0; i < tabPage.length; i++) {
if (url.indexOf(tabPage[i]) == 0) {
isTab = true
break
}
}
}
return isTab
}
let goto = (url: string, jumpType: JumpType = JumpType.navigator) => {
let isTab = checkIsTab(url)
if (isTab) {
jumpType = JumpType.switchTab
}
if (jumpType == JumpType.navigator) {
// @ts-ignore
this.$Router.push(url)
// uni.navigateTo({url: url});
} else if (jumpType == JumpType.switchTab) {
// @ts-ignore
this.$Router.pushTab(url)
// let baseUrl = url.split('?')
// if (baseUrl[1]) {
// this.$Router.pushTab(baseUrl[0])
// } else {
// this.$Router.pushTab(url)
// }
// uni.switchTab({url: baseUrl})
} else if (jumpType == JumpType.redirect) {
// @ts-ignore
this.$Router.replace(url)
// uni.redirectTo({url: url})
}
}
if (url) {
if (delay > 0) {
let timer = setTimeout(() => {
goto(url, jumpType)
}, delay)
} else {
goto(url, jumpType)
}
} else {
goto('/pages/index/index', JumpType.redirect)
}
},
goBack() {
let pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack({})
} else {
this.goto('')
}
},
/**
* @description
* @param url
*/
saveInPhoto(url: string) {
// #ifdef APP-PLUS
uni.showLoading({
// @ts-ignore
title: '加载中'
})
uni.downloadFile({
url,
success: (res) => {
uni.hideLoading()
if (res.statusCode === 200) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
showToast('保存成功')
},
fail: () => {
showToast('保存失败')
}
})
} else {
showToast('下载失败')
}
}
})
// #endif
},
/**
*
* @param url
* @param defaultUrl
*/
getFullImageUrl(url: string, defaultUrl: string = ''): string {
if (!url) {
return defaultUrl
}
if (url.startsWith('http://') || url.startsWith('https://')) {
return url
}
return `${PUBLIC_PATH_URL}${url}`
},
/**
*
* @param value
* @param fmt
*/
formatDateTime(value: string, fmt: string = 'YYYY-MM-DD HH:mm:ss'): string {
if (!value) return ''
return dateFormat(value, fmt)
},
/**
*
* @param value
*/
formatHtmlContent(value: string): string {
if (!value) return ''
return formatRichText(value)
},
// 解析url
parseUrl(url: string) {
const params = url.split('?')[1]
if (!params) return null
const paramsArr = params.split('&')
const paramsObj: any = {}
paramsArr.forEach((item: string) => {
const key = item.split('=')[0]
paramsObj[key] = item.split('=')[1]
})
return paramsObj
}
}
})
}
}

92
src/pages.json Normal file
View File

@ -0,0 +1,92 @@
{
"easycom": {
"autoscan": true,
"custom": {
// uni-ui
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
//pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/login/index",
"name": "loginIndex",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"disableScroll": true,
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/index/index",
"name": "index",
"style": {
"navigationBarTitleText": "首页",
"navigationStyle": "custom",
"disableScroll": false,
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/mine/index",
"name": "mine",
"style": {
"navigationBarTitleText": "我的",
"enablePullDownRefresh": false,
"navigationStyle": "custom",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/404",
"name": "404",
"style": {
"navigationBarTitleText": "404",
"enablePullDownRefresh": false,
"app-plus": {}
}
},
{
"path": "pages/webView/index",
"style": {
"app-plus": {
"titleNView": ""
}
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#F8F8F8",
"rpxCalcMaxDeviceWidth": 960,
// rpx px 960
"rpxCalcBaseDeviceWidth": 375,
// rpx 使 rpx px 375
"rpxCalcIncludeWidth": 750
// rpx rpx 750
},
"tabBar": {
"custom": true,
"color": "#999AAA",
"selectedColor": "#333444",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index"
},
{
"pagePath": "pages/mine/index"
}
]
}
}

11
src/pages/404.vue Normal file
View File

@ -0,0 +1,11 @@
<template>
<div>404</div>
</template>
<script>
export default {
name: 'NotFound'
}
</script>
<style scoped></style>

398
src/pages/index/index.vue Normal file
View File

@ -0,0 +1,398 @@
<template>
<view class="page_class">
<view class="top_nav">
<nav-bar :showBack="false">
<template #title>
<text>首页</text>
</template>
</nav-bar>
</view>
<tab-bar :pagePath="'/pages/index/index'"></tab-bar>
</view>
</template>
<script>
export default {
name: 'Index',
data() {
return {
}
},
onLoad() {
},
onShow() {
},
onReachBottom() {},
methods: {}
}
</script>
<style scoped lang="scss">
@import '@/static/style/public';
.page_class {
font-family: 'PingFang SC';
.top_nav {
display: flex;
flex-direction: column;
.nav_box {
width: 100%;
padding: 0 30rpx;
margin-top: -215rpx;
}
}
.index_img {
position: fixed;
top: 0;
width: 100%;
height: 430rpx;
}
.index_content {
z-index: 9;
.sift_content {
display: flex;
align-items: center;
padding: 0 32rpx;
.sift_name {
flex: 1;
padding: 16rpx 40rpx;
display: flex;
align-items: center;
border-radius: 50rpx;
background: #fff7df;
box-shadow: 0 10rpx 10rpx 0 #d59d004d;
margin-right: 30rpx;
.sift_name_icon {
flex-shrink: 0;
width: 28rpx;
height: 28rpx;
margin-right: 15rpx;
}
.sift_name_text {
width: 100%;
font-size: 28rpx;
line-height: 28rpx;
}
}
.sift_box {
display: flex;
align-items: center;
border-radius: 50rpx;
background: #ecb100;
box-shadow: 0 10rpx 10rpx 0 #d59d004d;
padding: 26rpx 40rpx;
.sift_box_icon {
width: 27rpx;
height: 27rpx;
flex-shrink: 0;
margin-right: 15rpx;
}
.sift_box_text {
color: #ffffff;
font-size: 28rpx;
line-height: 30rpx;
}
}
}
.checkup_box {
padding: 55rpx 32rpx;
margin-top: 30rpx;
border-radius: 40rpx 40rpx 0 0;
background: #f2f3f5;
.sift_tabs {
position: relative;
display: flex;
align-items: center;
overflow: auto;
.sift_tabs_item {
display: flex;
flex-direction: column;
justify-content: space-between;
text-align: center;
flex-shrink: 0;
color: #1d2129;
font-size: 30rpx;
font-weight: 400;
line-height: 32rpx;
margin-right: 50rpx;
height: 60rpx;
&:last-child {
margin-right: 50rpx;
}
.item_img {
width: 55rpx;
height: 21rpx;
margin-left: 12%;
}
}
.tabs_item_active {
color: #1d2129;
font-size: 34rpx;
font-weight: bold;
}
}
.not_data {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
.not_icon {
width: 306rpx;
height: 300rpx;
}
.not_text {
color: #999999;
font-size: 28rpx;
font-weight: 400;
line-height: 30rpx;
}
}
.sift_list {
padding-top: 30rpx;
.sift_item {
padding: 40rpx 30rpx 33rpx;
margin-bottom: 30rpx;
border-radius: 20rpx;
background: #fff;
box-shadow: 0 0 15rpx 0 #0000000d;
&:last-child {
margin: 0;
}
.item_head {
font-family: 'PingFang SC';
font-size: 28rpx;
line-height: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 30rpx;
border-bottom: 1rpx solid #eaeaee;
}
.item_content {
margin: 30rpx 0;
font-family: 'PingFang SC';
line-height: 32rpx;
.info_box {
display: flex;
align-items: center;
color: #333333;
font-size: 30rpx;
font-weight: 500;
margin-bottom: 25rpx;
}
.info_class {
color: #333333;
font-size: 28rpx;
font-weight: 400;
}
}
.item_foot {
display: flex;
align-items: center;
color: #666666;
text-align: justify;
font-family: 'PingFang SC';
font-size: 24rpx;
font-weight: 400;
line-height: 26rpx;
.foot_btn {
border-radius: 50rpx;
border: 1rpx solid #ccc;
padding: 15rpx 17rpx;
}
.foot_btn_active {
margin-right: 15rpx;
}
}
}
}
}
}
.search_box {
height: 100vh;
width: 100%;
background-color: rgba(0, 0, 0, 0.4);
position: fixed;
.search_content {
padding: 40rpx;
border-radius: 0 0 20rpx 20rpx;
background: #fff;
box-shadow: 0 4rpx 18rpx 0 #ffb2001a;
.head {
padding: 0 20rpx 24rpx;
display: flex;
align-items: center;
color: #1d2129;
font-size: 30rpx;
font-weight: 500;
line-height: 36rpx;
view {
margin-right: 30rpx;
&:first-child {
width: 53%;
}
&:nth-child(2) {
width: 15%;
margin-right: 44rpx;
}
&:last-child {
margin-right: 0;
flex: 1;
}
}
}
.class_list {
width: 100%;
color: #888888;
font-size: 30rpx;
line-height: 36rpx;
display: flex;
max-height: 408rpx;
margin-bottom: 40rpx;
.item_box {
margin-right: 10rpx;
height: 408rpx;
overflow: auto;
&:last-child {
margin-right: 0;
}
.class_item {
padding: 17rpx 20rpx;
border-radius: 10rpx;
}
.item_school_text {
width: 100%;
@include text_multiline(1);
}
.class_item_active {
background: #fef5eb;
color: #f58300;
}
}
}
.bottom {
display: flex;
justify-content: space-evenly;
align-content: center;
}
}
}
.consent_box {
padding: 40rpx 40rpx calc(env(safe-area-inset-bottom) + 18rpx);
border-radius: 20rpx 20rpx 0 0;
background: #fff;
box-shadow: 0 4rpx 18rpx 0 #ffb2001a;
.consent_head {
display: flex;
justify-content: flex-end;
align-items: center;
color: #1d2129;
font-size: 32rpx;
font-weight: 500;
line-height: 40rpx;
margin-bottom: 20rpx;
.consent_title {
margin-right: 227rpx;
}
.consent_icon {
width: 27rpx;
height: 27rpx;
}
}
.consent_info {
color: #333333;
font-size: 30rpx;
font-weight: 500;
line-height: 32rpx;
display: flex;
align-items: center;
margin-bottom: 30rpx;
}
.consent_list {
.consent_item {
padding: 34rpx 0;
border-top: 1rpx solid #eeeff2;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
font-weight: 400;
line-height: 32rpx;
&:last-child {
padding: 15rpx 0;
}
.item_title {
color: #333333;
}
.sign_img {
width: 176rpx;
height: 100rpx;
}
}
}
}
::v-deep .input-placeholder {
color: #e3b841;
}
::v-deep .uni-popup__wrapper {
pointer-events: auto;
}
}
</style>

170
src/pages/login/index.vue Normal file
View File

@ -0,0 +1,170 @@
<template>
<view class="page_class" :style="{ paddingTop: `${getNavHeightCss()}px` }">
<view class="top_nav">
<nav-bar :showBack="false" background-color="#fff">
<template #title>
<text>登录</text>
</template>
</nav-bar>
</view>
<button @click="goto('/pages/index/index',JumpType.switchTab)">去首页</button>
<!-- 隐私协议 -->
<uni-popup ref="protocolPopup" type="center" :is-mask-click="false" style="z-index: 99999">
<view class="popup">
<view class="popup_title">用户隐私保护提示</view>
<view class="popup_text">
亲爱的用户感谢您的信任您使用本小程序提供的产品服务前应当阅读并同意
<text style="color: #f96fb8; display: inline-block" @click="handOpenPrivacyContract">{{ miniText }}</text>
当您点击同意并开始使用产品服务时即表示你已理解并同息该条款内容该条款将对您产生法律约束力如您拒绝将退出小程序
</view>
<view class="btn_box">
<view class="cancel_btn" @click="closeMiniPrograms">不同意</view>
<button class="confirm_btn" open-type="agreePrivacyAuthorization" @agreeprivacyauthorization="handleAgreePrivacyAuthorization">同意</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import {JumpType} from "@/utils/common";
export default {
name: 'Index',
components: {},
data() {
return {
openId: '',
miniText: '',
isConfirmProtocol: true,
protocolCheck: null,
codeInterval: null
}
},
computed: {
JumpType() {
return JumpType
}
},
onLoad() {
wx.getPrivacySetting({
success: (result) => {
if (result?.needAuthorization) {
this.miniText = result.privacyContractName
}
},
fail: () => {},
complete: () => {}
})
uni.login({
success: async ({ code } = {}) => {
// openId
// const openIdResult = await getOpenId(code)
// if (openIdResult?.data) {
// const { openId } = openIdResult.data
// this.openId = openId
// }
}
})
},
onReachBottom() {},
methods: {
handleAgreePrivacyAuthorization() {
this.$refs.protocolPopup.close()
this.isConfirmProtocol = true
},
authorization() {
this.$refs.protocolPopup.open()
wx.getPrivacySetting({
success: (result) => {
if (result?.needAuthorization) {
this.miniText = result.privacyContractName
this.$refs.protocolPopup.open()
}
},
fail: () => {},
complete: () => {}
})
},
closeMiniPrograms() {
this.isConfirmProtocol = false
this.$refs.protocolPopup.close()
},
handOpenPrivacyContract() {
//
wx.openPrivacyContract({
success: () => {}, //
fail: () => {}, //
complete: () => {}
})
}
}
}
</script>
<style scoped lang="scss">
.page_class {
background-color: white;
.top_nav {
display: flex;
flex-direction: column;
border-bottom: 1rpx solid #e5e6eb;
.nav_box {
width: 100%;
padding: 0 30rpx;
margin-top: -215rpx;
}
}
.popup {
margin: 0 auto;
width: 70%;
padding: 30rpx;
background-color: white;
text-align: center;
border-radius: 30rpx;
.popup_title {
margin-bottom: 30rpx;
}
.popup_text {
text-align: left;
word-break: break-all;
margin-bottom: 30rpx;
}
.btn_box {
display: flex;
align-content: center;
justify-content: space-around;
.cancel_btn {
border-radius: 30rpx;
background-color: #f4f4f4;
font-size: 26rpx;
width: 200rpx;
text-align: center;
color: black;
line-height: 66rpx;
}
.confirm_btn {
border-radius: 30rpx;
background-color: #fcbd00;
color: white;
font-size: 26rpx;
line-height: 66rpx;
text-align: center;
}
button {
border: none;
width: 200rpx;
font-size: 26rpx;
padding: 0;
margin: 0;
}
}
}
}
::v-deep .placeholder-class {
font-size: 24rpx;
}
</style>

View File

@ -0,0 +1,73 @@
<template>
<view class="page_class" :style="{ paddingTop: `${getNavHeightCss()}px` }">
<view class="top_nav">
<nav-bar background-color="#fff" @leftClick="goBack">
<template #title>
<text>{{ titleType[title] }}</text>
</template>
</nav-bar>
</view>
<view class="content">
<rich-text :nodes="formatHtmlContent(content)"></rich-text>
</view>
</view>
</template>
<script>
import userApi from '@/request/module/userApi'
import { get } from '@/request'
export default {
components: {},
data() {
return {
title: '',
content: '',
protocolCheck: false,
titleType: {
privacy: '隐私协议',
user: '用户协议'
}
}
},
onLoad(options) {
if (options?.type) {
this.title = options.type
this.getDetail(options.typeId)
}
},
onReachBottom() {},
methods: {
async getDetail(type) {
const res = await get({
url: userApi.agreement,
data: { type }
})
if (res) {
this.content = res.data.content
}
}
}
}
</script>
<style scoped lang="scss">
.page_class {
background-color: white;
.top_nav {
display: flex;
flex-direction: column;
border-bottom: 1rpx solid #e5e6eb;
.nav_box {
width: 100%;
padding: 0 30rpx;
margin-top: -215rpx;
}
}
.content {
word-break: break-all;
padding: 40rpx;
font-size: 28rpx;
}
}
</style>

76
src/pages/mine/index.vue Normal file
View File

@ -0,0 +1,76 @@
<template>
<view class="page_class">
<nav-bar :showBack="false">
<template #title>
<text>我的</text>
</template>
</nav-bar>
<double-confirm ref="bookingPopup" title="确定要退出登录吗?" cancelText="取消" confirmText="确定" @confirm="confirmOutLogin" />
<tab-bar :pagePath="'/pages/mine/index'"></tab-bar>
</view>
</template>
<script>
import { mapState } from 'vuex'
import DoubleConfirm from '@/components/doubleConfirm/index.vue'
import { mobileFormat } from '@/utils/util'
export default {
name: 'Mine',
components: { DoubleConfirm },
data() {
return {
}
},
computed: {
...mapState({
info: (state) => state.UserStore.userInfo
})
},
onShow() {
this.getUserInfoData()
},
methods: {
mobileFormat,
async getUserInfoData() {
// const result = await getUserInfo()
// if (result?.data) {
// await store.dispatch('UserStore/setUserInfo', result.data)
// }
},
async confirmOutLogin() {
const result = await logout()
if (result) {
uni.clearStorageSync()
setTimeout(() => {
uni.reLaunch({
url: '/pages/login/index'
})
})
}
},
}
}
</script>
<style lang="scss" scoped>
@import '@/static/style/public';
.page_class {
width: 100%;
.top_header {
position: absolute;
top: 0;
width: 100%;
height: 500rpx;
z-index: 0;
&_image {
width: 100%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,23 @@
<template>
<web-view :src="url" allow :title="title" />
</template>
<script>
export default {
name: 'cusWebView',
data() {
return {
url: '',
title: ''
}
},
onLoad(options) {
this.url = decodeURIComponent(options?.url)
},
onReady() {
uni.setNavigationBarTitle({
title: this.title
})
}
}
</script>

132
src/request/index.ts Normal file
View File

@ -0,0 +1,132 @@
import { HttpMethod } from '@/utils/https'
import { CodeStatus } from '@/utils/common'
import { API_URL, getToken, setToken, showToast } from '@/utils/util'
import store from '@/store'
interface RequestData {
type: HttpMethod
url: string
data?: any
header?: any
notice?: boolean
returnData?: boolean
}
export const ContentTypeEnum = {
JSON: 'application/json;charset=UTF-8',
FORM: 'application/x-www-form-urlencoded',
FORM_DATA: 'multipart/form-data'
}
let requestCount = 0 // 请求计数器
const showLoading = () => {
if (requestCount === 0) {
uni.showLoading({ mask: true })
}
requestCount++
}
const hideLoading = () => {
if (requestCount <= 1) {
uni.hideLoading()
}
if (requestCount > 0) {
requestCount--
}
}
export const request = ({ type, url, data, header = {}, returnData, notice }: RequestData) => {
return new Promise((resolve) => {
if (notice) {
showLoading()
}
uni.request({
method: type,
url: API_URL + url,
data,
header: {
// 医生小程序token
assessToken: getToken(),
// 医院管理后台token
// adminAuthToken: getToken(),
...header
},
success: async (res: any) => {
if (res.data.code === CodeStatus.SUCCESS) {
return resolve(returnData ? res : res.data)
}
if (res.data.code === CodeStatus.NO_LOGIN || res.data.code === CodeStatus.SYSTEM_ERROR) {
setToken('')
await store.dispatch('UserStore/setUserInfo', null)
await uni.reLaunch({ url: '/pages/login/login' })
return resolve(null)
}
return resolve(null)
},
fail: (err) => {
return resolve(null)
},
complete: (res: any) => {
if (notice) {
hideLoading()
}
if (res.data.code !== CodeStatus.SUCCESS) {
showToast(res.data.msg)
}
}
})
})
}
interface RequestParams {
url: string
data?: any
header?: any
returnData?: boolean
notice?: boolean
}
export const get = ({ url, data, header, returnData = false, notice = true }: RequestParams): Promise<null | any> => {
return request({ type: HttpMethod.GET, url, data, header, returnData, notice })
}
export const post = ({ url, data, header, returnData = false, notice = true }: RequestParams): Promise<null | any> => {
return request({ type: HttpMethod.POST, url, data, header, returnData, notice })
}
export const del = ({ url, data, header, returnData = false, notice = true }: RequestParams): Promise<null | any> => {
return request({ type: HttpMethod.DELETE, url, data, header, returnData, notice })
}
export const put = ({ url, data, header, returnData = false, notice = true }: RequestParams): Promise<null | any> => {
return request({ type: HttpMethod.PUT, url, data, header, returnData, notice })
}
export const uploadFile = ({ url = '', tempFilePaths = [] }): Promise<null | any> => {
return new Promise((resolve) => {
uni.showLoading({
mask: true
})
uni.uploadFile({
url: API_URL + url, // 仅为示例,非真实的接口地址
filePath: tempFilePaths[0],
name: 'file',
header: {
assessToken: getToken()
},
success: (uploadFileRes) => {
uni.hideLoading()
const result = JSON.parse(uploadFileRes.data)
return resolve(result)
},
fail: (err) => {
uni.hideLoading()
showToast(err.errMsg)
return resolve(null)
}
})
})
}

View File

@ -0,0 +1,14 @@
import { post } from '@/request'
const userApi = {
login: '/api/login',
}
type loginParams = {
username: string
password: string
}
export const login = (data: loginParams) => post({ url: userApi.login, data })
export default userApi

38
src/router.ts Normal file
View File

@ -0,0 +1,38 @@
import { createRouter, RouterMount, totalNextRoute } from 'uni-simple-router'
import { getToken, getUserInfo } from '@/utils/util'
const router = createRouter({
platform: process.env.VUE_APP_PLATFORM,
routes: [...ROUTES, { path: '*', redirect: '/pages/404' }]
})
router.beforeEach(async (to: totalNextRoute, from: totalNextRoute, next) => {
next()
// const loginPathList = ['/pages/login/index', '/pages/login/protocol', '/pages/login/again']
// const token = getToken()
// const userInfo = getUserInfo()
//
// if ((!token && !userInfo) || (token && !userInfo)) {
// // 用户未登录
// if (!loginPathList.includes(to.path)) {
// const redirect = encodeURIComponent(JSON.stringify(to.fullPath || '/pages/index/index'))
// next({ path: `/pages/login/index?redirect=${redirect}` })
// } else {
// next()
// }
// } else {
// // 用户已登录
// if (to.path === '/pages/login/index') {
// // 已登录用户访问登录页面,跳转至首页
// next({ path: '/pages/index/index' })
// }
// // 其他情况,正常跳转
// next()
// }
})
router.afterEach((to: totalNextRoute, from: totalNextRoute) => {
// console.info('afterEach to', to, 'afterEach from', from)
})
export { router, RouterMount }

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 719 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

View File

@ -0,0 +1,101 @@
@import './uni-scss/index';
page,
view,
scroll-view,
swiper,
swiper-item,
movable-area,
movable-view,
cover-view,
cover-image,
icon,
text,
rich-text,
progress,
button,
checkbox-group,
checkbox,
form,
input,
label,
picker,
picker-view,
radio-group,
radio,
slider,
switch,
textarea,
navigator,
functional-page-navigator,
image,
video,
camera,
live-player,
live-pusher,
map,
canvas,
open-data,
web-view,
ad {
box-sizing: border-box;
&::after {
box-sizing: border-box;
}
&::before {
box-sizing: border-box;
}
&::-webkit-scrollbar {
display: none;
}
}
pre {
white-space: pre-wrap;
}
/*清除浮动*/
.clearfix:after {
content: '';
display: block;
height: 0;
overflow: hidden;
clear: both;
position: relative;
}
/*单行文本切割*/
.text-ellipsis {
white-space: nowrap;
word-break: keep-all;
overflow: hidden;
text-overflow: ellipsis;
}
/*多行省略*/
@mixin text_multiline($line: 2) {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: $line;
overflow: hidden;
word-break: break-all;
}
.icon {
position: relative;
display: inline-block;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
}
.flex-center {
display: flex;
align-items: center;
}
.uni-modal .uni-modal__bd {
word-break: keep-all;
}

View File

@ -0,0 +1 @@
@import 'styles/index';

View File

@ -0,0 +1,7 @@
@import 'setting/variables';
@import 'setting/border';
@import 'setting/color';
@import 'setting/space';
@import 'setting/radius';
@import 'setting/text';
@import 'setting/styles';

View File

@ -0,0 +1,3 @@
.uni-border {
border: 1px $uni-border-1 solid;
}

View File

@ -0,0 +1,65 @@
// TODO 暂时不需要 class 需要用户使用变量实现 如果使用类名其实并不推荐
// @mixin get-styles($k,$c) {
// @if $k == size or $k == weight{
// font-#{$k}:#{$c}
// }@else{
// #{$k}:#{$c}
// }
// }
$uni-ui-color: (
// 主色
primary: $uni-primary,
primary-disable: $uni-primary-disable,
primary-light: $uni-primary-light,
// 辅助色
success: $uni-success,
success-disable: $uni-success-disable,
success-light: $uni-success-light,
warning: $uni-warning,
warning-disable: $uni-warning-disable,
warning-light: $uni-warning-light,
error: $uni-error,
error-disable: $uni-error-disable,
error-light: $uni-error-light,
info: $uni-info,
info-disable: $uni-info-disable,
info-light: $uni-info-light,
// 中性色
main-color: $uni-main-color,
base-color: $uni-base-color,
secondary-color: $uni-secondary-color,
extra-color: $uni-extra-color,
// 背景色
bg-color: $uni-bg-color,
// 边框颜色
border-1: $uni-border-1,
border-2: $uni-border-2,
border-3: $uni-border-3,
border-4: $uni-border-4,
// 黑色
black: $uni-black,
// 白色
white: $uni-white,
// 透明
transparent: $uni-transparent
) !default;
@each $key, $child in $uni-ui-color {
.uni-#{'' + $key} {
color: $child;
}
.uni-#{'' + $key}-bg {
background-color: $child;
}
}
.uni-shadow-sm {
box-shadow: $uni-shadow-sm;
}
.uni-shadow-base {
box-shadow: $uni-shadow-base;
}
.uni-shadow-lg {
box-shadow: $uni-shadow-lg;
}
.uni-mask {
background-color: $uni-mask;
}

View File

@ -0,0 +1,55 @@
@mixin radius($r, $d: null, $important: false) {
$radius-value: map-get($uni-radius, $r) if($important, !important, null);
// Key exists within the $uni-radius variable
@if (map-has-key($uni-radius, $r) and $d) {
@if $d == t {
border-top-left-radius: $radius-value;
border-top-right-radius: $radius-value;
} @else if $d == r {
border-top-right-radius: $radius-value;
border-bottom-right-radius: $radius-value;
} @else if $d == b {
border-bottom-left-radius: $radius-value;
border-bottom-right-radius: $radius-value;
} @else if $d == l {
border-top-left-radius: $radius-value;
border-bottom-left-radius: $radius-value;
} @else if $d == tl {
border-top-left-radius: $radius-value;
} @else if $d == tr {
border-top-right-radius: $radius-value;
} @else if $d == br {
border-bottom-right-radius: $radius-value;
} @else if $d == bl {
border-bottom-left-radius: $radius-value;
}
} @else {
border-radius: $radius-value;
}
}
@each $key, $child in $uni-radius {
@if ($key) {
.uni-radius-#{'' + $key} {
@include radius($key);
}
} @else {
.uni-radius {
@include radius($key);
}
}
}
@each $direction in t, r, b, l, tl, tr, br, bl {
@each $key, $child in $uni-radius {
@if ($key) {
.uni-radius-#{'' + $direction}-#{'' + $key} {
@include radius($key, $direction, false);
}
} @else {
.uni-radius-#{$direction} {
@include radius($key, $direction, false);
}
}
}
}

View File

@ -0,0 +1,55 @@
@mixin fn($space, $direction, $size, $n) {
@if $n {
#{$space}-#{$direction}: #{$size * $uni-space-root}px;
} @else {
#{$space}-#{$direction}: #{-$size * $uni-space-root}px;
}
}
@mixin get-styles($direction, $i, $space, $n) {
@if $direction == t {
@include fn($space, top, $i, $n);
}
@if $direction == r {
@include fn($space, right, $i, $n);
}
@if $direction == b {
@include fn($space, bottom, $i, $n);
}
@if $direction == l {
@include fn($space, left, $i, $n);
}
@if $direction == x {
@include fn($space, left, $i, $n);
@include fn($space, right, $i, $n);
}
@if $direction == y {
@include fn($space, top, $i, $n);
@include fn($space, bottom, $i, $n);
}
@if $direction == a {
@if $n {
#{$space}: #{$i * $uni-space-root}px;
} @else {
#{$space}: #{-$i * $uni-space-root}px;
}
}
}
@each $orientation in m, p {
$space: margin;
@if $orientation == m {
$space: margin;
} @else {
$space: padding;
}
@for $i from 0 through 16 {
@each $direction in t, r, b, l, x, y, a {
.uni-#{$orientation}#{$direction}-#{$i} {
@include get-styles($direction, $i, $space, true);
}
.uni-#{$orientation}#{$direction}-n#{$i} {
@include get-styles($direction, $i, $space, false);
}
}
}
}

View File

@ -0,0 +1,162 @@
/* #ifndef APP-NVUE */
$-color-white: #fff;
$-color-black: #000;
@mixin base-style($color) {
color: #fff;
background-color: $color;
border-color: mix($-color-black, $color, 8%);
&:not([hover-class]):active {
background: mix($-color-black, $color, 10%);
border-color: mix($-color-black, $color, 20%);
color: $-color-white;
outline: none;
}
}
@mixin is-color($color) {
@include base-style($color);
&[loading] {
@include base-style($color);
&::before {
margin-right: 5px;
}
}
&[disabled] {
&,
&[loading],
&:not([hover-class]):active {
color: $-color-white;
border-color: mix(darken($color, 10%), $-color-white);
background-color: mix($color, $-color-white);
}
}
}
@mixin base-plain-style($color) {
color: $color;
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 70%);
&:not([hover-class]):active {
background: mix($-color-white, $color, 80%);
color: $color;
outline: none;
border-color: mix($-color-white, $color, 50%);
}
}
@mixin is-plain($color) {
&[plain] {
@include base-plain-style($color);
&[loading] {
@include base-plain-style($color);
&::before {
margin-right: 5px;
}
}
&[disabled] {
&,
&:active {
color: mix($-color-white, $color, 40%);
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 80%);
}
}
}
}
.uni-btn {
margin: 5px;
color: #393939;
border: 1px solid #ccc;
font-size: 16px;
font-weight: 200;
background-color: #f9f9f9;
// TODO 暂时处理边框隐藏一边的问题
overflow: visible;
&::after {
border: none;
}
&:not([type]),
&[type='default'] {
color: #999;
&[loading] {
background: none;
&::before {
margin-right: 5px;
}
}
&[disabled] {
color: mix($-color-white, #999, 60%);
&,
&[loading],
&:active {
color: mix($-color-white, #999, 60%);
background-color: mix($-color-white, $-color-black, 98%);
border-color: mix($-color-white, #999, 85%);
}
}
&[plain] {
color: #999;
background: none;
border-color: $uni-border-1;
&:not([hover-class]):active {
background: none;
color: mix($-color-white, $-color-black, 80%);
border-color: mix($-color-white, $-color-black, 90%);
outline: none;
}
&[disabled] {
&,
&[loading],
&:active {
background: none;
color: mix($-color-white, #999, 60%);
border-color: mix($-color-white, #999, 85%);
}
}
}
}
&:not([hover-class]):active {
color: mix($-color-white, $-color-black, 50%);
}
&[size='mini'] {
font-size: 16px;
font-weight: 200;
border-radius: 8px;
}
&.uni-btn-small {
font-size: 14px;
}
&.uni-btn-mini {
font-size: 12px;
}
&.uni-btn-radius {
border-radius: 999px;
}
&[type='primary'] {
@include is-color($uni-primary);
@include is-plain($uni-primary);
}
&[type='success'] {
@include is-color($uni-success);
@include is-plain($uni-success);
}
&[type='error'] {
@include is-color($uni-error);
@include is-plain($uni-error);
}
&[type='warning'] {
@include is-color($uni-warning);
@include is-plain($uni-warning);
}
&[type='info'] {
@include is-color($uni-info);
@include is-plain($uni-info);
}
}
/* #endif */

View File

@ -0,0 +1,24 @@
@mixin get-styles($k, $c) {
@if $k == size or $k == weight {
font-#{$k}: #{$c};
} @else {
#{$k}: #{$c};
}
}
@each $key, $child in $uni-headings {
/* #ifndef APP-NVUE */
.uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k, $c);
}
}
/* #endif */
/* #ifdef APP-NVUE */
.container .uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k, $c);
}
}
/* #endif */
}

View File

@ -0,0 +1,162 @@
// @use "sass:math";
@import '../tools/functions';
// 间距基础倍数
$uni-space-root: 2 !default;
// 边框半径默认值
$uni-radius-root: 5px !default;
$uni-radius: () !default;
// 边框半径断点
$uni-radius: map-deep-merge(
(
0: 0,
// TODO 当前版本暂时不支持 sm 属性
// 'sm': math.div($uni-radius-root, 2),
null: $uni-radius-root,
'lg': $uni-radius-root * 2,
'xl': $uni-radius-root * 6,
'pill': 9999px,
'circle': 50%
),
$uni-radius
);
// 字体家族
$body-font-family: 'Roboto', sans-serif !default;
// 文本
$heading-font-family: $body-font-family !default;
$uni-headings: () !default;
$letterSpacing: -0.01562em;
$uni-headings: map-deep-merge(
(
'h1': (
size: 32px,
weight: 300,
line-height: 50px,
// letter-spacing:-0.01562em
),
'h2': (
size: 28px,
weight: 300,
line-height: 40px,
// letter-spacing: -0.00833em
),
'h3': (
size: 24px,
weight: 400,
line-height: 32px,
// letter-spacing: normal
),
'h4': (
size: 20px,
weight: 400,
line-height: 30px,
// letter-spacing: 0.00735em
),
'h5': (
size: 16px,
weight: 400,
line-height: 24px,
// letter-spacing: normal
),
'h6': (
size: 14px,
weight: 500,
line-height: 18px,
// letter-spacing: 0.0125em
),
'subtitle': (
size: 12px,
weight: 400,
line-height: 20px,
// letter-spacing: 0.00937em
),
'body': (
font-size: 14px,
font-weight: 400,
line-height: 22px,
// letter-spacing: 0.03125em
),
'caption': (
'size': 12px,
'weight': 400,
'line-height': 20px,
// 'letter-spacing': 0.03333em,
// 'text-transform': false
)
),
$uni-headings
);
// 主色
$uni-primary: #2979ff !default;
$uni-primary-disable: lighten($uni-primary, 20%) !default;
$uni-primary-light: lighten($uni-primary, 25%) !default;
// 辅助色
// 除了主色外的场景色需要在不同的场景中使用例如危险色表示危险的操作
$uni-success: #18bc37 !default;
$uni-success-disable: lighten($uni-success, 20%) !default;
$uni-success-light: lighten($uni-success, 25%) !default;
$uni-warning: #f3a73f !default;
$uni-warning-disable: lighten($uni-warning, 20%) !default;
$uni-warning-light: lighten($uni-warning, 25%) !default;
$uni-error: #e43d33 !default;
$uni-error-disable: lighten($uni-error, 20%) !default;
$uni-error-light: lighten($uni-error, 25%) !default;
$uni-info: #8f939c !default;
$uni-info-disable: lighten($uni-info, 20%) !default;
$uni-info-light: lighten($uni-info, 25%) !default;
// 中性色
// 中性色用于文本背景和边框颜色通过运用不同的中性色来表现层次结构
$uni-main-color: #3a3a3a !default; // 主要文字
$uni-base-color: #6a6a6a !default; // 常规文字
$uni-secondary-color: #909399 !default; // 次要文字
$uni-extra-color: #c7c7c7 !default; // 辅助说明
// 边框颜色
$uni-border-1: #f0f0f0 !default;
$uni-border-2: #ededed !default;
$uni-border-3: #dcdcdc !default;
$uni-border-4: #b9b9b9 !default;
// 常规色
$uni-black: #000000 !default;
$uni-white: #ffffff !default;
$uni-transparent: rgba(
$color: #000000,
$alpha: 0
) !default;
// 背景色
$uni-bg-color: #f7f7f7 !default;
/* 水平间距 */
$uni-spacing-sm: 8px !default;
$uni-spacing-base: 15px !default;
$uni-spacing-lg: 30px !default;
// 阴影
$uni-shadow-sm: 0 0 5px
rgba(
$color: #d8d8d8,
$alpha: 0.5
) !default;
$uni-shadow-base: 0 1px 8px 1px
rgba(
$color: #a5a5a5,
$alpha: 0.2
) !default;
$uni-shadow-lg: 0px 1px 10px 2px
rgba(
$color: #a5a4a4,
$alpha: 0.5
) !default;
// 蒙版
$uni-mask: rgba(
$color: #000000,
$alpha: 0.4
) !default;

View File

@ -0,0 +1,29 @@
// 合并 map
@function map-deep-merge($parent-map, $child-map) {
$result: $parent-map;
@each $key, $child in $child-map {
$parent-has-key: map-has-key($result, $key);
$parent-value: map-get($result, $key);
$parent-type: type-of($parent-value);
$child-type: type-of($child);
$parent-is-map: $parent-type == map;
$child-is-map: $child-type == map;
@if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)) {
$result: map-merge(
$result,
(
$key: $child
)
);
} @else {
$result: map-merge(
$result,
(
$key: map-deep-merge($parent-value, $child)
)
);
}
}
@return $result;
}

View File

@ -0,0 +1,34 @@
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root: 5px;
// 主色
$uni-primary: #2979ff;
// 辅助色
$uni-success: #4cd964;
// 警告色
$uni-warning: #f0ad4e;
// 错误色
$uni-error: #dd524d;
// 描述色
$uni-info: #909399;
// 中性色
$uni-main-color: #303133;
$uni-base-color: #606266;
$uni-secondary-color: #909399;
$uni-extra-color: #c0c4cc;
// 背景色
$uni-bg-color: #f5f5f5;
// 边框颜色
$uni-border-1: #dcdfe6;
$uni-border-2: #e4e7ed;
$uni-border-3: #ebeef5;
$uni-border-4: #f2f6fc;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba(
$color: #000000,
$alpha: 0
);

View File

@ -0,0 +1,80 @@
@import 'styles/setting/variables';
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root: 5px;
// 主色
$uni-primary: #2979ff;
$uni-primary-disable: mix(#fff, $uni-primary, 50%);
$uni-primary-light: mix(#fff, $uni-primary, 80%);
// 辅助色
// 除了主色外的场景色需要在不同的场景中使用例如危险色表示危险的操作
$uni-success: #18bc37;
$uni-success-disable: mix(#fff, $uni-success, 50%);
$uni-success-light: mix(#fff, $uni-success, 80%);
$uni-warning: #f3a73f;
$uni-warning-disable: mix(#fff, $uni-warning, 50%);
$uni-warning-light: mix(#fff, $uni-warning, 80%);
$uni-error: #e43d33;
$uni-error-disable: mix(#fff, $uni-error, 50%);
$uni-error-light: mix(#fff, $uni-error, 80%);
$uni-info: #8f939c;
$uni-info-disable: mix(#fff, $uni-info, 50%);
$uni-info-light: mix(#fff, $uni-info, 80%);
// 中性色
// 中性色用于文本背景和边框颜色通过运用不同的中性色来表现层次结构
$uni-main-color: #3a3a3a; // 主要文字
$uni-base-color: #6a6a6a; // 常规文字
$uni-secondary-color: #909399; // 次要文字
$uni-extra-color: #c7c7c7; // 辅助说明
// 边框颜色
$uni-border-1: #f0f0f0;
$uni-border-2: #ededed;
$uni-border-3: #dcdcdc;
$uni-border-4: #b9b9b9;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba(
$color: #000000,
$alpha: 0
);
// 背景色
$uni-bg-color: #f7f7f7;
/* 水平间距 */
$uni-spacing-sm: 8px;
$uni-spacing-base: 15px;
$uni-spacing-lg: 30px;
// 阴影
$uni-shadow-sm: 0 0 5px
rgba(
$color: #d8d8d8,
$alpha: 0.5
);
$uni-shadow-base: 0 1px 8px 1px
rgba(
$color: #a5a5a5,
$alpha: 0.2
);
$uni-shadow-lg: 0px 1px 10px 2px
rgba(
$color: #a5a4a4,
$alpha: 0.5
);
// 蒙版
$uni-mask: rgba(
$color: #000000,
$alpha: 0.4
);

34
src/store/index.ts Normal file
View File

@ -0,0 +1,34 @@
import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
import UserStore from './modules/user'
const store = new Vuex.Store({
state: {
// 在此定义状态
navHeight: 0
},
getters: {
// 在此定义 getter 函数
getNavHeight(state: any) {
return state.navHeight
}
},
mutations: {
// 在此定义 mutation 函数
setNavHeight(state: any, height: number) {
state.navHeight = height
}
},
actions: {
// 在此定义 action 函数
SetNavHeight({ commit }: any, height: number) {
commit('setNavHeight', height)
}
},
modules: {
UserStore,
}
})
export default store

29
src/store/modules/user.js Normal file
View File

@ -0,0 +1,29 @@
import { getUserInfo, setUserInfo } from '@/utils/util'
const prevUserInfo = getUserInfo()
export default {
namespaced: true,
state: {
userInfo: prevUserInfo || {},
registerInfo: {},
isLogin: !!prevUserInfo
},
getters: {
// 在此定义 getter 函数
getUserInfo(state) {
return state.userInfo
}
},
mutations: {
changeUserInfo(state, data) {
state.userInfo = data
state.isLogin = !!data
setUserInfo(state.userInfo)
}
},
actions: {
setUserInfo({ commit }, data) {
commit('changeUserInfo', data)
}
}
}

76
src/uni.scss Normal file
View File

@ -0,0 +1,76 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color: #333; // 基本色
$uni-text-color-inverse: #fff; // 反色
$uni-text-color-grey: #999; // 辅助灰色如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* 背景颜色 */
$uni-bg-color: #fff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
/* 边框颜色 */
$uni-border-color: #c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16;
/* 图片尺寸 */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2c405a; // 文章标题颜色
$uni-font-size-title: 20px;
$uni-color-subtitle: #555; // 二级标题颜色
$uni-font-size-subtitle: 18px;
$uni-color-paragraph: #3f536e; // 文章段落颜色
$uni-font-size-paragraph: 15px;

21
src/utils/common.ts Normal file
View File

@ -0,0 +1,21 @@
export enum JumpType {
navigator,
switchTab,
redirect
}
export class PagesParams {
current: number = 1
size: number = 10
total: number = 0
}
export enum CodeStatus {
// 请求成功
SUCCESS = 0,
// 未登录
NO_LOGIN = 1000,
// 系统错误
SYSTEM_ERROR = 502
}

44
src/utils/https.ts Normal file
View File

@ -0,0 +1,44 @@
// HTTP请求方法枚举
export enum HttpMethod {
GET = 'GET',
POST = 'POST',
PUT = 'PUT',
DELETE = 'DELETE'
}
// HTTP请求配置
export interface RequestConfig {
/** API路径 */
url?: string
/** Method类型 */
method?: HttpMethod
/** 接口返回数据 */
data?: any
/** showLoading 加载中 */
showLoading?: boolean
/** hiddenToast 隐藏错误提示 */
hiddenToast?: boolean
/** loadingTitle 加载title */
loadingTitle?: string
/** Header头部 */
header?: object
}
// 继承中间类型data声明为any
interface AnyResult extends WechatMiniprogram.RequestSuccessCallbackResult {
data: any
}
// 从中间类型继承一个泛型接口data声明为泛型
export interface SpecResult<T> extends AnyResult {
data: T
}
// 声明业务数据类型
export interface MyAwesomeData {
code: number
msg: string
data: any
rows?: any
total?: number
}

124
src/utils/util.ts Normal file
View File

@ -0,0 +1,124 @@
import dayjs, { QUnitType } from 'dayjs'
import duration from 'dayjs/plugin/duration'
import md5 from 'crypto-js/md5'
const VUE_APP_STORAGE_PREFIX = process.env.VUE_APP_STORAGE_PREFIX
export const setToken = (token: string) => {
uni.setStorageSync(`${VUE_APP_STORAGE_PREFIX}_TOKEN`, token)
}
export const getToken = () => {
return uni.getStorageSync(`${VUE_APP_STORAGE_PREFIX}_TOKEN`)
}
export const setUserInfo = (data: any) => {
uni.setStorageSync(`${VUE_APP_STORAGE_PREFIX}_USER_INFO`, JSON.stringify(data))
}
export const getUserInfo = () => {
const data = uni.getStorageSync(`${VUE_APP_STORAGE_PREFIX}_USER_INFO`)
try {
if (data) return JSON.parse(data)
} catch (e) {
return null
}
}
/**
*
* @param {string} originalHtml - HTML
* @returns {string} - HTML
*/
export const formatRichText = (originalHtml: string): string => {
if (!originalHtml) return ''
// 解码 HTML 实体并移除 <br/> 标签
let formattedHtml = originalHtml
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/<br\s*\/?>/gi, '')
// 调整 <img> 标签以实现响应式,并移除宽度和高度的内联样式
formattedHtml = formattedHtml.replace(/<img([^>]*?)(style="[^"]*")?([^>]*?)>/gi, (match, pre, style, post) => {
return `<img${pre}${post} style="width:100%;height:auto;display:block;margin:0;">`
})
// 确保所有内联样式使用 max-width 实现响应式
formattedHtml = formattedHtml.replace(/<(table)?[^>]*style="([^"]*)"[^>]*>/gi, (fullMatch, isTable, styles) => {
let responsiveStyles
if (isTable) {
responsiveStyles = styles.replace(/height\s*:\s*[^;]+;?/gi, 'height:auto;')
} else {
responsiveStyles = styles.replace(/width\s*:\s*[^;]+;?/gi, 'max-width:100%;').replace(/height\s*:\s*[^;]+;?/gi, 'height:auto;')
}
return fullMatch.replace(`style="${styles}"`, `style="${responsiveStyles}"`)
})
// 保留 <a>、<table>、<blockquote> 等标签
formattedHtml = formattedHtml.replace(/<(a|table|blockquote)([^>]*)>/gi, (match, tag, attrs) => {
return `<${tag}${attrs}>`
})
return formattedHtml
}
// 显示toast提示
export const showToast = (title: string = '加载中', duration: number = 2000, onClose?: Function) => {
uni.showToast({
title,
duration,
icon: 'none',
mask: true
})
if (onClose) {
setTimeout(() => {
onClose()
}, duration)
}
}
// 格式化时间
export const dateFormat = (time: string, format?: string, isTime = false) => {
if (isTime) {
dayjs.extend(duration)
const timeData = dayjs.duration(time)
return timeData.format(format)
}
return dayjs(time).format(format || 'YYYY-MM-DD HH:mm')
}
// 求时间差
export const diffTime = (time = new Date(), initTime = new Date(), unit: QUnitType = 'day') => {
return dayjs(time).diff(initTime, unit)
}
// 验证手机号
export const checkMobile = (value: string) => {
return /^1[3456789]\d{9}$/.test(value)
}
// 验证邮箱
export const checkEmail = (value: string) => {
return /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])/.test(
value
)
}
// 给手机号码格式化加*
export const mobileFormat = (value: string) => {
return value?.replace(/(\d{3})\d*(\d{4})/, '$1****$2')
}
// md5 加密
export function encryptByMd5(password: string) {
return md5(password).toString()
}
// 深拷贝
export const deepCopy = (obj: any) => JSON.parse(JSON.stringify(obj))
export const stringToObject = (data: string | object) => (typeof data === 'string' ? JSON.parse(data) : data)
export const API_URL = process.env.VUE_APP_BASE_API
export const PUBLIC_PATH_URL = process.env.VUE_APP_PUBLIC_PATH_URL

23
tsconfig.json Normal file
View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"sourceMap": true,
"allowJs": true,
"skipLibCheck": true,
"baseUrl": ".",
"types": ["webpack-env", "@dcloudio/types", "miniprogram-api-typings", "mini-types"],
"paths": {
"@/*": ["./src/*"]
},
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"exclude": ["node_modules", "unpackage", "dist", "src/**/*.nvue", "doc", "src/i18n"]
}

39
vue.config.js Normal file
View File

@ -0,0 +1,39 @@
const TransformPages = require('uni-read-pages')
const ESLintPlugin = require('eslint-webpack-plugin')
const { webpack } = new TransformPages()
const path = require('path')
const resolve = (dir) => {
return path.join(__dirname, dir)
}
module.exports = {
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
devServer: {
hot: true,
port: 8088
},
transpileDependencies: ['@dcloudio/uni-ui', 'uni-simple-router', '/node_modules/uni-simple-router'],
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
ROUTES: webpack.DefinePlugin.runtimeValue(() => {
const tfPages = new TransformPages({
includes: ['path', 'name', 'aliasPath', 'needLogin']
})
return JSON.stringify(tfPages.routes)
}, true)
}),
new ESLintPlugin({
fix: true,
emitError: true,
emitWarning: true
})
],
resolve: {
alias: {
'@': resolve('src'),
'@/static': resolve('static')
}
}
}
}

9467
yarn.lock Normal file

File diff suppressed because it is too large Load Diff