中拓产业云(北京)科技服务有限公司

Commit 7e9d72fd authored by 佟春晓's avatar 佟春晓
Browse files

local

parents
Showing with 1341 additions and 0 deletions
+1341 -0
.gitignore 0 → 100644
.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
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
README.md 0 → 100644
# project_name
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
STANDARD.md 0 → 100644
#Vue规范文档
#规范目的
为提高团队协作效率
便于后台人员添加功能及前端后期优化维护
输出高质量的文档
#规范等级
| 级别 | 描述 |
| ---- | ---- |
| 1 | 严格执行 |
| 2 | 需要按照规范执行,但规范可能变动 |
| 3 | 时间相对充裕时执行,紧急任务可暂缓执行,后续需补充 |
| 4 | 时间相对充裕时执行,紧急任务可暂缓执行,后续视情况补充 |
| 5 | 视情况相对执行 |
#结构化规范
##Uni-App [级别:1]
dist 编译文件目录
public H5等首页文件目录
src 源码目录
|-- api 请求路径以及函数 (js相关文件)
|-- common 公共目录 (js相关文件)
|-- components 公用组件 (uni组件直接放在目录内)
|-- Dialog 项目共用组件(只有当前项目会多处使用的组件、按类别放在各自文件夹内 参见 封装规范 - 组件封装)
|-- Object 私有组件(个人使用的组件 参见 封装规范 - 组件封装)
|-- pages 主要文件目录(登录与首页相关文件、在此目录内编写)
|-- pages**** 分包1 (根据底部菜单分包)
|-- pages**** 分包2 (根据底部菜单分包)
|-- static 静态文件目录(小型图片、icon、文档等)
|-- store vuex, 统一管理
#格式规范(基本根据EsLink规范)
##缩进[级别:1]
代码首列编写,每级别按照俩个空格进行缩进
##空格[级别:1]
冒号与逗号前无空格,后有空格
小括号前后都无需空格,函数,判断等需要在括号外 有空格
其他符号前后都需有空格
##分号[级别:1]
代码结束换行无分号
##文件默认结构编写顺序和规则[级别:1]
文件顺序:template -> script -> style
script编写顺序:components -> props -> data -> 生命周期函数 -> computed -> watch -> methods
#命名规范
##变量命名规范[级别:1]
驼峰命名: 变量类型+变量名称+变量名称 例: strName, iNumber, arrNames, listNames, objNames, isName(Boolean), jsonName
##函数命名[级别:1]
驼峰命名: 动作+名称+名称
##文件命名
###文件夹、文件、组件[级别:1]
都以首字母小写驼峰命名
###组件命名[级别:2]
私有组件The或以父组件名称开头, 公用组件按分组名称开头。例: UploadImages + UploadCropperImages
###js、css文件[级别:1]
小写加下划线连接命名 upload_images.js
##全局变量命名[级别:1]
全大写以下划线相连
##缓存变量命名[级别:1]
项目名称+全大写以下划线相连
#封装规范
##组件封装
###私有组件[级别:1]
私有组件封装在当前模块内的components文件夹下,数量少以父组件为头命名方式。数量多,按照父组件在components文件夹下新建父组件名称文件夹放置私有组件
###项目公共组件[级别:1]
项目公共组件放置在根目录的components-> dialog -> 模块名称 文件夹内
###公共组件[级别:1]
公共组件以文件夹形式放置在根目录的components内
如果是完全与当前项目无耦合的组件 请尽量上传到NPM后安装使用[级别:4]
##JS封装
###当前页面函数[级别:1]
有任何一次复用的函数 需要封装
函数操作逻辑过长 请按照事件逻辑 封装每部的函数 [级别:5]
###项目公共函数[级别:1]
常用的函数请封装至common
大批量页面都会使用的函数 请在main.js内注册 [级别:4]
###公共函数[级别:1]
动态函数 放置common文件内
静态js函数 请放置在static -> js文件内
如果完全无耦合 请尽量上传到NPM后安装使用[级别:4]
#样式规范
##命名规范[级别:1]
小写加"-"连接命名 list-title
##样式编码[级别:1]
使用sass编码语言
##样式表文件位置[级别:1]
样式表文件放置在static -> css 文件夹内
其他样式文件放置在相关文件下内
相似的文件样式需封装在所属文件夹下 [级别:5]
尽量避免文件内部长篇css编码 [级别:5]
##根目录文件解析[级别:1]
global 封装基础样式编码、所有颜色变量、相关样式函数
common 特殊公用样式表 [级别:5]
#注释规范
## 注释位置[级别:1]
1: 文件头部注释 使用文件注释
2: 自定义函数注释 使用函数注释
3: 简易函数注释(无变量 或 系统变量, 单逻辑) 使用单行 或 逻辑注释
4: 组件props 推荐使用默认定义形式, 传值超过3个,必须使用默认值定义 , ['1', '2', '3'] 使用区块注释 默认值方式,使用逻辑注释
5: 文件内data 使用后缀注释,单行注释,逻辑注释
6: 复杂函数 使用逻辑注释
7: 复杂页面 使用区块注释
8: 根目录README 文件时时更新 [级别:4]
##HTML 模块注释
<!-- 文章列表模块 -->
<div class="article-list">
...
</div>
##HTML 区块注释
<!--
@name 文章列表
@description 用于展示文章列表
-->
##JS 后缀注释
this.getList() // 基础数据请求完成之后执行的方法
data () {
return {
list: [], // 文章列表
type: 0 // 文章类型 [0: 全部 1: 热门 2: 置顶]
}
}
##JS 单行注释
// 获取文章列表
##JS 逻辑注释
/* 获取文章列表 */
##JS 区块注释
<!--
@param 变量: 描述
@param 变量: 描述
-->
##JS 函数注释
/**
* 函数描述
* 与此函数相关联引入的其他函数,并说明该函数具体位置以及说明其功能
* @param {string} p1 参数1的说明
* @param {string} p2 参数2的说明,比较长
* 那就换行了.
* @param {number=} p3 参数3的说明(可选)
* @return {Object} 返回值描述
*/
## 文件注释
/**
* @File 文件名称
* @FileDescription 文件描述
* @Author user@meizu.com
* @Date 2021-05-19
* @Update user(2021-05-19)
*/
<!--
* @File 文件名称
* @FileDescription 文件描述
* @Author user@meizu.com
* @Date 2021-05-19
* @Update user(2021-05-19)
-->
#特殊注意事项
-: 所有请求统一封装
-: api请求地址 外部跳转地址统一封装
-: Js代码清除console.log和debugger后提交
-: 页面this 变量赋值 统一为 _this 建议使用 .bind(this)
-: 尽量调整好警告后提交
-: 尽量使用 ===
-: 元素值为整型时 使用 :value='1'
-: 搜索条件加.trim 去除空格
-: 时间格式、金额格式加转换
-: 样式格需要固定大小的 需要加隐藏
#常用变量名称表
##函数动词
1 get 获取/set 设置,
2 add 增加/remove 删除
3 create 创建/destory 移除
4 start 启动/stop 停止
5 open 打开/close 关闭,
6 read 读取/write 写入
7 load 载入/save 保存,
8 create 创建/destroy 销毁
9 begin 开始/end 结束,
10 backup 备份/restore 恢复
11 import 导入/export 导出,
12 split 分割/merge 合并
13 inject 注入/extract 提取,
14 attach 附着/detach 脱离
15 bind 绑定/separate 分离,
16 view 查看/browse 浏览
17 edit 编辑/modify 修改,
18 select 选取/mark 标记
19 copy 复制/paste 粘贴,
20 undo 撤销/redo 重做
21 insert 插入/delete 移除,
22 add 加入/append 添加
23 clean 清理/clear 清除,
24 index 索引/sort 排序
25 find 查找/search 搜索,
26 increase 增加/decrease 减少
27 play 播放/pause 暂停,
28 launch 启动/run 运行
29 compile 编译/execute 执行,
30 debug 调试/trace 跟踪
31 observe 观察/listen 监听,
32 build 构建/publish 发布
33 input 输入/output 输出,
34 encode 编码/decode 解码
35 encrypt 加密/decrypt 解密,
36 compress 压缩/decompress 解压缩
37 pack 打包/unpack 解包,
38 parse 解析/emit 生成
39 connect 连接/disconnect 断开,
40 send 发送/receive 接收
41 download 下载/upload 上传,
42 refresh 刷新/synchronize 同步
43 update 更新/revert 复原,
44 lock 锁定/unlock 解锁
45 check out 签出/check in 签入,
46 submit 提交/commit 交付
47 push 推/pull 拉,
48 expand 展开/collapse 折叠
49 begin 起始/end 结束,
50 start 开始/finish 完成
51 enter 进入/exit 退出,
52 abort 放弃/quit 离开
53 obsolete 废弃/depreciate 废旧,
54 collect 收集/aggregate 聚集
##内容
1: 头:header  
2: 内容:content/container
3: 尾:footer  
4: 导航:nav  
5: 侧栏:sidebar
6: 栏目:column  
7: 页面外围控制整体布局宽度:wrapper  
8: 左右中:left right center
9: 登录条:loginbar  
10: 标志:logo  
11: 广告:banner  
12: 页面主体:main  
13: 热点:hot
14: 新闻:news  
15: 下载:download  
16: 子导航:subnav  
17: 菜单:menu
18: 子菜单:submenu  
19: 搜索:search  
20: 友情链接:friendlink  
21: 页脚:footer
22: 版权:copyright  
23: 滚动:scroll  
24: 内容:content  
25: 标签页:tab
26: 文章列表:list  
27: 提示信息:msg  
28: 小技巧:tips  
29: 栏目标题:title
30: 加入:joinus  
31: 指南:guild  
32: 服务:service  
33: 注册:regsiter
34: 状态:status  
35: 投票:vote  
\ No newline at end of file
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}`
}
}
])
})
module.exports = {
presets: [
[
'@vue/app',
{
modules: 'commonjs',
useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry'
}
]
],
plugins
}
This diff is collapsed.
{
"name": "project_name",
"version": "0.1.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:custom": "cross-env NODE_ENV=production uniapp-cli custom",
"build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build",
"build:mp-360": "cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build",
"build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build",
"build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build",
"build:mp-kuaishou": "cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build",
"build:mp-qq": "cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build",
"build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build",
"build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build",
"build:quickapp-native": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build",
"build:quickapp-webview": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build",
"build:quickapp-webview-huawei": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build",
"build:quickapp-webview-union": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build",
"dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch",
"dev:custom": "cross-env NODE_ENV=development uniapp-cli custom",
"dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve",
"dev:mp-360": "cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch",
"dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch",
"dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch",
"dev:mp-kuaishou": "cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch",
"dev:mp-qq": "cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch",
"dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao 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:quickapp-native": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch",
"dev:quickapp-webview": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch",
"dev:quickapp-webview-huawei": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch",
"dev:quickapp-webview-union": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch",
"info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js",
"serve:quickapp-native": "node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js",
"test:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i",
"test:h5": "cross-env UNI_PLATFORM=h5 jest -i",
"test:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i",
"test:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i",
"test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i"
},
"dependencies": {
"@dcloudio/uni-app-plus": "^2.0.0-31920210709003",
"@dcloudio/uni-h5": "^2.0.0-31920210709003",
"@dcloudio/uni-helper-json": "*",
"@dcloudio/uni-i18n": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-360": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-alipay": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-baidu": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-kuaishou": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-qq": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-toutiao": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-vue": "^2.0.0-31920210709003",
"@dcloudio/uni-mp-weixin": "^2.0.0-31920210709003",
"@dcloudio/uni-quickapp-native": "^2.0.0-31920210709003",
"@dcloudio/uni-quickapp-webview": "^2.0.0-31920210709003",
"@dcloudio/uni-stat": "^2.0.0-31920210709003",
"@vue/shared": "^3.0.0",
"core-js": "^3.6.5",
"flyio": "^0.6.2",
"node-sass": "^6.0.1",
"regenerator-runtime": "^0.12.1",
"sass-loader": "^5.0.0",
"vue": "^2.6.11",
"vuex": "^3.2.0"
},
"devDependencies": {
"@babel/runtime": "~7.12.0",
"@dcloudio/types": "*",
"@dcloudio/uni-automator": "^2.0.0-31920210709003",
"@dcloudio/uni-cli-shared": "^2.0.0-31920210709003",
"@dcloudio/uni-migration": "^2.0.0-31920210709003",
"@dcloudio/uni-template-compiler": "^2.0.0-31920210709003",
"@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.0-31920210709003",
"@dcloudio/vue-cli-plugin-uni": "^2.0.0-31920210709003",
"@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.0-31920210709003",
"@dcloudio/webpack-uni-mp-loader": "^2.0.0-31920210709003",
"@dcloudio/webpack-uni-pages-loader": "^2.0.0-31920210709003",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-service": "~4.5.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",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [
"Android >= 4",
"ios >= 8"
],
"uni-app": {
"scripts": {}
}
}
const path = require('path')
module.exports = {
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')
]
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px'
})
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>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
\ No newline at end of file
<script>
import {
mapState,
mapMutations
} from 'vuex'
export default {
onLaunch: function() {
console.log('App Launch');
let uniIdToken = uni.getStorageSync('uni_id_token')
if (uniIdToken) {
this.login(uni.getStorageSync('username'))
}
// #ifdef APP-PLUS
// 一键登录预登陆,可以显著提高登录速度
uni.preLogin({
provider: 'univerify',
success: (res) => {
this.setUniverifyErrorMsg()
this.setHideUniverify(false);
console.log("preLogin success: ", res);
},
fail: (err) => {
this.setUniverifyErrorMsg(err.errMsg)
// 没有开通一键登录
this.setHideUniverify(true);
console.log("preLogin fail: ", err);
}
})
// #endif
},
onShow: function() {
console.log('App Show');
},
onHide: function() {
console.log('App Hide');
},
methods: {
...mapMutations(['login', 'setUniverifyErrorMsg', 'setHideUniverify']),
}
}
</script>
<style lang="scss">
/* #ifndef APP-PLUS-NVUE */
@import "./static/css/global"; /* 通用组件、模板样式库,可以当作一套ui库应用 */
/* #endif */
</style>
MIT License
Copyright (c) 2018 DCloud
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# uni-template-login
基于 uni-app & uniCloud 的前后一体登录模板
![](https://img-cdn-qiniu.dcloud.net.cn/7E6B79E2-B469-4CF3-8F4D-7502E72C4CB8.png?imageView2/0/w/375)
![](https://img-cdn-qiniu.dcloud.net.cn/659AE293-95F8-46E1-AC1F-D62FE3B080DB.png?imageView2/0/w/375)
## 快速体验
手机扫码体验:
![](https://img.cdn.aliyun.dcloud.net.cn/uni-app/uni-template-login-qr.png)
## 本地运行
1. 将项目拖入[HBuilderX](http://www.dcloud.io/hbuilderx.html)
2. 创建服务空间,详情参考[uniCloud 快速上手](https://uniapp.dcloud.net.cn/uniCloud/quickstart)
3. 上传 common 下的公用模块、在云函数 user-center 内安装 uni-id 模块并上传,[公用模块参考文档](https://uniapp.dcloud.io/uniCloud/cf-common)
4. 在 cloudfunctions 目录下的`db_init.json`右键初始化云数据库
5. 运行到 HBuilderX 内置浏览器体验
6. 如果运行到小程序,注意在小程序后台配置域名白名单,[详见](https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=%e5%b0%8f%e7%a8%8b%e5%ba%8f%e4%b8%ad%e4%bd%bf%e7%94%a8unicloud%e7%9a%84%e7%99%bd%e5%90%8d%e5%8d%95%e9%85%8d%e7%bd%ae)
## 特点
- 前端基于uni-app实现,支持所有平台
- 服务端基于 uniCloud 实现,用户管理基于 [uni-id](https://uniapp.dcloud.net.cn/uniCloud/uni-id) 实现
- 使用 vuex 管理登录状态
- 支持账号密码、手机号验证等多种登录模式
- 支持裂变,可以邀请用户注册
\ No newline at end of file
const configAccount = uni.getAccountInfoSync()
const BASE_URL = configAccount.miniProgram.envVersion == 'release' ? "https://api.hongkun.ii-park.com" : "https://api.test.ii-park.com" // 请求开发域名
const BASE_DATA_URL = "https://api.data.ii-park.com" // 数据中台开发域名
const imgShowUrl = 'https://zfgk-middle-platform.oss-cn-beijing.aliyuncs.com/static/space/CRM/' // 请求图片资源路径
const api = {
base_url: BASE_URL,
// 基础数据
base: {
dict: '/space/data/base/list', // 获取基础数据列表 1服务配套;2搜索关键字;3所属行业;4招商方向;5产业特色;6土地规划用途
upload: '/universal/files/upload', // 文件上传
areas: '/information/areas/list', // 获取省市区
qrCode: '/universal/qrcode/generate_base64', // 获取二维码By Base64
imgShowUrl: BASE_URL + '/universal/files/download?object_name=', // 上传文件路役
pdfDownloadUrl: BASE_URL + '/space/parks/pdf/download' // 上传文件路役
},
// 用户
user: {
Login: '/users/users/login-by-account', // 账号登录
mobileLogin: '/users/users/login-by-mobile', // 账号短信登陆
ForgePassword: '/auth/forge-password', // 忘记密码
Register: '/auth/register', // 注册
UserInfo: '/users/users/item', // 获取用户信息
UserMenu: '/user/nav', // 获取用户菜单
ResetPwd: '/users/users/reset-password-by-mobile', // 手机重置密码
ImgCaptcha: '/universal/files/image_captcha', // 获取图形验证码
SendSms: '/message/sms/send-captcha', // 发送短信验证码
resetPassword: '/users/users/reset-password', // 修改密码
editUser: '/users/users/edit', // 修改用户
messageList: '/message/internal/records/list', // 信息列表
changeMessageStatus: '/message/internal/records/status', // 信息改为已读
getPicCode: '/universal/files/image_captcha'
}
}
export default api
import request from '@/common/request'
import api from '@/api/api'
export function getPicCode (parameter) {
return request({
url: api.user.getPicCode,
method: 'get',
data: parameter
})
}
export function login (parameter) {
return request({
url: api.user.Login,
method: 'post',
data: parameter
})
}
export function mobileLogin (parameter) {
return request({
url: api.user.mobileLogin,
method: 'post',
data: parameter
})
}
export function getSmsCaptcha (parameter) {
return request({
url: api.user.SendSms,
method: 'post',
data: parameter
})
}
export function getInfo (parameter) {
return request({
url: api.user.UserInfo,
method: 'get',
params: parameter
})
}
export function getIncubatorId (parameter) {
return request({
url: api.user.getIncubatorId,
method: 'get'
})
}
export function getFunctions (parameter) {
return request({
url: api.user.functionsList,
method: 'get',
params: parameter
})
}
export function getCurrentUserNav () {
return request({
url: api.user.UserMenu,
method: 'get'
})
}
export function getImgCaptcha () {
return request({
url: api.user.ImgCaptcha,
method: 'get'
})
}
export function sendCaptcha (parameter) {
return request({
url: api.user.SendCapt,
method: 'post',
data: parameter
})
}
export function resetPwd (parameter) {
return request({
url: api.user.ResetPwd,
method: 'post',
data: parameter
})
}
export function resetPassword (parameter) {
return request({
url: api.user.resetPassword,
method: 'post',
data: parameter
})
}
export function edituser (parameter) {
return request({
url: api.user.editUser,
method: 'post',
data: parameter
})
}
// 信息列表
export function getMessageList (parameter) {
return request({
url: api.user.messageList,
method: 'get',
params: parameter
})
}
// 信息标记为已读
export function changeMessageStatus (parameter) {
return request({
url: api.user.changeMessageStatus,
method: 'post',
data: parameter
})
}
// 通过token获取用户信息
export function getUserInfo (parameter) {
return request({
url: api.user.UserInfo,
method: 'get',
params: parameter
})
}
\ No newline at end of file
## 0.2.23(2021-05-27)
- 升级uni-id到3.1.0版本,默认对邮箱、用户名忽略大小写 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=case-sensitive)
## 0.2.22(2021-04-13)
- 升级uni-id到3.0.12版本,去除bindTokenToDevice配置
## 0.2.21(2021-04-13)
- 发布测试
## 0.2.20(2021-03-02)
- 修复user-center云函数中从上下文读取数据错误
- 部分uni-ui插件改为uni_modules引入
## 0.2.19(2021-03-01)
- 调整为uni_modules目录规范
import api from '@/api/api'
/**
* 默认配置
**/
const config = {
baseURL: api.base_url,
header: {
'content-type': 'application/json'
},
dataType: 'json',
responseType: 'text'
}
/**
* 请求函数
**/
function request(options = {}) {
options.baseURL = options.baseURL || config.baseURL
options.dataType = options.dataType || config.dataType
options.url = options.baseURL + options.url
options.data = options.data
options.header = {...options.header, ...config.header}
options.method = options.method || config.method
options = requestBefore(options)
return new Promise((resolve, reject) => {
options.success = function (res) {
const r = requestAfter(res)
r ? resolve(r) : reject(r)
}
options.fail = function (err) {
reject(requestAfter(err))
}
uni.request(options)
})
}
/**
* 请求拦截器
* 添加自定义请求参数
*
* @param {options} 默认请求参数
* @return {options} 变更后的请求参数
**/
function requestBefore(options) {
if (uni.getStorageSync('ACCESS_TOKEN')) {
options.header['Authorization'] = 'Bearer ' + uni.getStorageSync('ACCESS_TOKEN');
}
options.header['zf-client-id'] = getUUID()
return options
}
/**
* 响应拦截器
* 处理请求返回结果
*
* @param {response} 请求返回结果
* @return {options} 同步返回处理结果
**/
function requestAfter(response) {
if (response.statusCode !== 200) {
const data = response.data
// 从 localstorage 获取 token
const token = uni.getStorageSync('ACCESS_TOKEN')
if (response.statusCode === 403 || response.statusCode === 422 || response.statusCode === 405 || response.statusCode === 500 || response.statusCode === 503) {
uni.showToast({
title: data.message || '系统内部错误,请联系维护人员',
icon:'none',
duration: 2000
})
} else if (response.statusCode === 400) {
uni.showToast({
title: typeof data.message === 'string' ? data.message : '系统内部错误,请联系维护人员',
icon:'none',
duration: 2000
})
} else if ((data.result && data.result.isLogin) || response.statusCode === 401) {
if (!token) {
uni.showToast({
title:"请登陆",
icon:'none',
duration: 2000
})
} else {
uni.showToast({
title: data.message || '系统内部错误,请联系维护人员',
icon:'none',
duration: 2000
})
}
} else if (response.statusCode === 401) {
uni.showToast({
title: data.message || '尚未登录或登录已过期,请重新登录',
icon:'none',
duration: 2000
})
} else {
uni.showToast({
title: data.message || '系统内部错误,请联系维护人员',
icon:'none',
duration: 2000
})
}
return false
}
return response.data
}
// 通过localStorage获取 UUID
function getUUID () {
if (uni.getStorageSync('ii-park-uuid')) {
return uni.getStorageSync('ii-park-uuid')
} else {
const uuid = generateUUID()
uni.setStorageSync('ii-park-uuid', uuid)
return uuid
}
}
// 创建UUID
function generateUUID () {
var d = new Date().getTime()
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0
d = Math.floor(d / 16)
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
})
return uuid
}
export default request
import Vuex from '@/store/index.js'
export function univerifyLogin() {
const commit = Vuex.commit;
const PROVIDER = 'univerify';
/**
* reject(true) 点击其他登录方式
* reject(false) 关闭登录框
*/
return new Promise((resolve, reject) => {
uni.getProvider({
service: 'oauth',
success: (res) => {
if (res.provider.indexOf(PROVIDER) !== -1) {
// 一键登录已在APP onLaunch的时候进行了预登陆,可以显著提高登录速度。登录成功后,预登陆状态会重置
uni.login({
provider: PROVIDER,
success: (res) => {
uni.closeAuthView();
uni.showLoading();
uniCloud.callFunction({
name: 'user-center',
data: {
action: 'loginByUniverify',
params: res.authResult
},
success: (e) => {
console.log('login success', e);
if (e.result.code == 0) {
const username = e.result.username || e.result.mobile || '一键登录新用户'
uni.setStorageSync('uni_id_token', e.result.token)
uni.setStorageSync('username', username)
uni.setStorageSync('login_type', 'online')
commit('login', username)
resolve();
uni.switchTab({
url: '../main/main',
});
} else {
uni.showModal({
title: `登录失败: ${e.result.code}`,
content: e.result.message,
showCancel: false
})
console.log('登录失败', e);
e.result.errMsg = e.result.message;
}
},
fail: (e) => {
uni.showModal({
title: `登录失败`,
content: e.errMsg,
showCancel: false
})
},
complete: () => {
uni.hideLoading()
}
})
},
fail: (err) => {
console.error('授权登录失败:' + JSON.stringify(err));
// 一键登录点击其他登录方式
if (err.code == 30002) {
uni.closeAuthView();
reject(true);
return;
}
// 关闭登录
if (err.code == 30003) {
uni.closeAuthView();
reject(false);
return;
}
reject(err);
}
})
} else {
reject();
}
},
fail: (err) => {
console.error('获取服务供应商失败:' + err.errMsg);
reject(err)
}
});
})
}
export function univerifyErrorHandler(err, cb) {
if (!err) {
cb && cb()
return
};
const state = Vuex.state;
const obj = {
/* showCancel: true,
cancelText: '其他登录方式',
success(res) {
if (res.cancel) {
cb && cb()
}
} */
}
switch (true) {
// 未开通
case err.code == 1000:
uni.showModal(Object.assign({
title: `登录失败`,
content: `${err.errMsg},错误码:${err.code}\n开通指南:https://ask.dcloud.net.cn/article/37965`,
}, obj));
break;
// 预登陆失败
case err.code == 30005:
uni.showModal(Object.assign({
showCancel: false,
title: `预登录失败`,
content: `${err.errMsg},错误码:${err.code}`
}, obj));
break;
//用户关闭验证界面
case err.code != 30003:
uni.showModal(Object.assign({
showCancel: false,
title: `登录失败`,
content: `${err.errMsg},错误码:${err.code}`,
}, obj));
break;
}
}
This diff is collapsed.
export function getDeviceUUID() {
let deviceId = uni.getStorageSync('uni_deviceId') ||
uni.getSystemInfoSync().deviceId ||
uni.getSystemInfoSync().system + '_' + Math.random().toString(36).substr(2);
uni.setStorageSync('uni_deviceId', deviceId)
return deviceId;
}
<template>
<uni-popup ref="login" background-color="#fff">
<view class="login-type">
<view v-for="(item,index) in listLoginType" :key="index" @click="iloginType = index; clearForm()" :class="{act: iloginType === index}"
class="login-type-btn">{{item}}</view>
</view>
<uni-forms ref="form" validateTrigger="bind" :rules="iloginType === 0 ? objMobileRules : ObjUserRules" :modelValue="param" class="login-form" style="background-color: #fff">
<view style="width: 80vw;">
<uni-forms-item :label="iloginType === 1 ? '账户' : '手机号'" labelWidth="85" :required='true' name="strUserName">
<uni-easyinput v-model="param.strUserName" :placeholder="iloginType === 1 ? '账户' : '手机号'" />
</uni-forms-item>
<uni-forms-item label="密码" labelWidth="85" :required='true' v-show='iloginType === 1' name="strPassword">
<uni-easyinput type="password" v-model="param.strPassword" placeholder="密码" />
</uni-forms-item>
<uni-forms-item label="图形验证码" labelWidth="85" :required='true' v-show='iloginType === 0' name="strCheck">
<uni-easyinput v-model="param.strCheck" placeholder="图形验证码" />
<img :src="objPicCode.image" alt="" class="img" @click="getPicCode">
</uni-forms-item>
<uni-forms-item label="验证码" labelWidth="85" :required='true' v-show='iloginType === 0' name="strCaptcha">
<uni-easyinput v-model="param.strCaptcha" placeholder="验证码" />
<button class="uni-btn-captcha" tabindex="-1" @click="getCaptcha" v-if="iTimerNum < 0">
获取验证码
</button>
<button class="uni-btn-captcha" tabindex="-1" v-if="iTimerNum > 0">
倒计时{{ iTimerNum }}s
</button>
<button class="uni-btn-captcha" tabindex="-1" @click="getCaptcha" v-if="iTimerNum == 0">
重新发送
</button>
</uni-forms-item>
<view class="uni-button-group pointer">
<button class="uni-button uni-button-full" type="primary" @click="submitForm">确定</button>
</view>
</view>
</uni-forms>
</uni-popup>
</template>
<script>
import { getSmsCaptcha, getPicCode, getMessageList } from '@/api/login'
import { mapActions } from 'vuex'
export default {
data () {
return {
iloginType: 1, // 0 免密登录 1 密码登录
listLoginType: ['免密登录', '密码登录'],
objPicCode: {
code: '',
image: ''
},
param: {
strCaptcha: '',
strCheck: '',
strPassword: '',
strUserName: ''
},
iTimerNum: -1, // 按钮倒计时
objMobileRules: {
strUserName: {
rules: [{
required: true,
errorMessage: '请输入用户手机或账号'
}]
},
strCheck: {
rules: [{
required: true,
errorMessage: '请输入图形验证码'
}]
},
strCaptcha: {
rules: [{
required: true,
errorMessage: '请输入验证码'
}]
}
},
ObjUserRules: {
strUserName: {
rules: [{
required: true,
errorMessage: '请输入用户手机或账号'
}]
},
strPassword: {
rules: [{
required: true,
errorMessage: '请输入用户密码'
}, {
minLength: 6,
maxLength: 24,
errorMessage: '密码长度在 6 到 24 个字符',
}]
}
}
}
},
mounted () {
},
created () {
},
methods: {
...mapActions(['Login', 'mobileLogin', 'GetInfo']),
// 显示登录窗口
showLogin () {
this.$refs.login.open('center')
this.getPicCode()
},
// 关闭登录窗口
closeLogin () {
this.$refs.login.close()
},
// 更新图形验证码
getPicCode () {
getPicCode().then(res => {
this.objPicCode.image = res.data.image
this.objPicCode.code = res.data.captcha_key
})
},
// 获取短信验证码
getCaptcha () {
this.$refs.form.validateField(['strUserName', 'strCheck']).then(res => {
this.iTimerNum = 60
const times = setInterval(() => {
if (this.iTimerNum-- === 0) clearInterval(times)
}, 1000)
const param = {
phone: res.strUserName,
image_captcha_key: this.objPicCode.code,
image_captcha_value: res.strCheck
}
getSmsCaptcha(param).then(res => {
if (res.data) {
uni.showToast({
title: '验证码已发送',
icon: 'none',
duration: 2000
})
}
})
})
},
// 提交登录
submitForm () {
this.$refs.form.validate().then((res)=>{
let functionLogin = null
const param = {}
if (this.iloginType === 1) { // 账号密码登陆
param.username = res.strUserName
param.password = res.strPassword
functionLogin = (param) => this.Login(param)
} else { // 账号短信登陆
param.a = res.strUserName
param.captcha = res.strCaptcha
functionLogin = (param) => this.mobileLogin(param)
}
functionLogin(param).then((res) => {
this.clearForm()
this.closeLogin()
}).catch(error => {})
})
},
clearForm () {
this.$refs.form.resetFields()
}
}
}
</script>
<style lang="scss" scoped>
.login-type {
padding: 12upx;
background-color: #FFF;
display: flex;
justify-content: center;
}
.login-type-btn {
line-height: 30px;
margin: 0px 15px;
}
.login-type-btn.act {
color: #0FAEFF;
border-bottom: solid 1px #0FAEFF;
}
.uni-input-border,
.uni-textarea-border {
width: 100%;
font-size: 14px;
color: #666;
border: 1px #e5e5e5 solid;
border-radius: 5px;
box-sizing: border-box;
}
.uni-input-border {
padding: 0 10px;
height: 35px;
}
.img{
position:absolute;
top: 0;
right: -1upx;
height: 70upx;
width: 200upx;
z-index: 2;
}
.icon{
position:absolute;
top: 15upx;
right: 5upx;
height: 20upx;
width: 80upx;
z-index: 2;
}
.uni-btn-captcha{
position:absolute;
top: 0;
right: -1upx;
height: 70upx;
width: 200upx;
z-index: 2;
font-size: 28upx;
color: #666666;
}
</style>
/**
* @desc 函数防抖
* @param func 目标函数
* @param wait 延迟执行毫秒数
* @param immediate true - 立即执行, false - 延迟执行
*/
export const debounce = function(func, wait = 1000, immediate = true) {
let timer;
console.log(1);
return function() {
console.log(123);
let context = this,
args = arguments;
if (timer) clearTimeout(timer);
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timer = setTimeout(() => {
func.apply(context, args);
}, wait)
}
}
}
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
*/
export const throttle = (func, wait = 1000, type = 1) => {
let previous = 0;
let timeout;
return function() {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment