初始化项目
|
|
@ -0,0 +1,3 @@
|
||||||
|
unpackage
|
||||||
|
node_modules
|
||||||
|
uview-ui
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
.DS_Store
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
unpackage/
|
||||||
|
.hbuilderx/
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
**/*.log
|
||||||
|
|
||||||
|
tests/**/coverage/
|
||||||
|
tests/e2e/reports
|
||||||
|
selenium-debug.log
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.local
|
||||||
|
.env.development
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<script>
|
||||||
|
import { calcDate } from '@/utils/date.js'
|
||||||
|
import { tokenTime } from '@/common/setting.js'
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return { refreshLock: false }
|
||||||
|
},
|
||||||
|
onLaunch: function() {
|
||||||
|
this.refreshToken()
|
||||||
|
console.log('App Launch')
|
||||||
|
},
|
||||||
|
onShow: function() {
|
||||||
|
console.log('App Show')
|
||||||
|
},
|
||||||
|
onHide: function() {
|
||||||
|
console.log('App Hide')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 定时检测token
|
||||||
|
refreshToken() {
|
||||||
|
this.refreshTime = setInterval(() => {
|
||||||
|
const token = uni.getStorageSync('token')
|
||||||
|
const date = calcDate(token.datetime, new Date().getTime())
|
||||||
|
if (!date) return
|
||||||
|
if (date.seconds >= tokenTime && !this.refreshLock) {
|
||||||
|
this.refreshLock = true
|
||||||
|
this.$u.api
|
||||||
|
.refreshToken(token.content, '000000')
|
||||||
|
.then(res => {
|
||||||
|
this.$u.func
|
||||||
|
.refreshToken(res)
|
||||||
|
.then(() => {
|
||||||
|
this.refreshLock = false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.refreshLock = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.refreshLock = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 30000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
/*uview全局样式*/
|
||||||
|
@import 'uview-ui/index.scss';
|
||||||
|
/*app全局样式*/
|
||||||
|
@import 'static/style/app.scss';
|
||||||
|
|
||||||
|
// 修改checkbox样式
|
||||||
|
checkbox.curdCheck .wx-checkbox-input,
|
||||||
|
checkbox.curdCheck .uni-checkbox-input {
|
||||||
|
border-radius: 50% !important;
|
||||||
|
border-color: #c8c9cc !important;
|
||||||
|
color: #5f88ff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkbox.curdCheck .wx-checkbox-input-checked,
|
||||||
|
checkbox.curdCheck .uni-checkbox-input-checked {
|
||||||
|
// background-color: #5f88ff;
|
||||||
|
color: #5f88ff !important;
|
||||||
|
border-color: #5f88ff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-picker-container,
|
||||||
|
.wx-picker-container {
|
||||||
|
z-index: 10074;
|
||||||
|
}
|
||||||
|
|
||||||
|
uni-modal {
|
||||||
|
z-index: 19999 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
BladeX商业授权许可协议
|
||||||
|
|
||||||
|
一、 知识产权:
|
||||||
|
BladeX系列产品知识产权归上海布雷德科技有限公司所有
|
||||||
|
|
||||||
|
二、 许可:
|
||||||
|
1. 在您完全接受并遵守本协议的基础上,本协议授予您使用BladeX的某些权利和非独占性许可。
|
||||||
|
2. 本协议中,将本产品使用用途分为“专业版用途”和“企业版用途”。
|
||||||
|
3. “专业版用途”定义:指个人在非团体机构中出于任何目的使用本产品(任何目的包括商业目的或非盈利目的)。
|
||||||
|
4. “企业版用途”定义:指团体机构(例如公司企业、政府、学校、军队、医院、社会团体等各类组织)(不包含集团,若集团使用则需为各个子公司分别购买企业授权)出于任何目的使用本产品(任何目的包括商业目的或非盈利目的)。
|
||||||
|
|
||||||
|
三、 约束和限制:
|
||||||
|
1. 本产品只能由您为本协议许可的目的而使用,您不得透露给任何第三方;
|
||||||
|
2. 从本产品取得的任何信息、软件、产品或服务,您不得对其进行修改、改编或基于以上内容创建同种类别的衍生产品并售卖。
|
||||||
|
3. 您不得对本产品以及与之关联的商业授权进行发布、出租、销售、分销、抵押、转让、许可或发放子许可证。
|
||||||
|
4. 本产品商业授权版可能包含一些独立功能或特性,这些功能只有在您购买商业授权后才可以使用。在未取得商业授权的情况下,您不得使用、尝试使用或复制这些授权版独立功能。
|
||||||
|
5. 若您的客户要求以源码方式交付软件,需缴纳企业版授权费用,否则本产品部分不得提供源码。
|
||||||
|
|
||||||
|
四、 不得用于非法或禁止的用途:
|
||||||
|
您在使用本产品或服务时,不得将本产品产品或服务用于任何非法用途或本协议条款、条件和声明禁止的用途。
|
||||||
|
|
||||||
|
五、 免责说明:
|
||||||
|
1. 本产品按“现状”授予许可,您须自行承担使用本产品的风险。BladeX团队不对此提供任何明示、暗示或任何其它形式的担保和表示。在任何情况下,对于因使用或无法使用本软件而导致的任何损失(包括但不仅限于商业利润损失、业务中断或业务信息丢失),BladeX团队无需向您或任何第三方负责,即使BladeX团队已被告知可能会造成此类损失。在任何情况下, BladeX团队均不就任何直接的、间接的、附带的、后果性的、特别的、惩戒性的和处罚性的损害赔偿承担任何责任,无论该主张是基于保证、合同、侵权(包括疏忽)或是基于其他原因作出。
|
||||||
|
2. 本产品可能内置有第三方服务,您应自行评估使用这些第三方服务的风险,由使用此类第三方服务而产生的纠纷,全部责任由您自行承担。
|
||||||
|
3. BladeX团队不对使用本产品构建的网站中任何信息内容以及导致的任何版权纠纷、法律争议和后果承担任何责任,全部责任由您自行承担。
|
||||||
|
4. BladeX团队可能会经常提供产品更新或升级,但BladeX团队没有为根据本协议许可的产品提供维护或更新的责任。
|
||||||
|
5. BladeX团队可能会按照官方制定的答疑规则为您进行答疑,但BladeX团队没有为根据本协议许可的产品提供技术支持的义务或责任。
|
||||||
|
|
||||||
|
六、 权利和所有权的保留:
|
||||||
|
BladeX团队保留所有未在本协议中明确授予您的所有权利。BladeX团队保留随时更新本协议的权利,并只需公示于对应产品项目的LICENSE文件,无需征得您的事先同意且无需另行通知,更新后的内容应于公示即时生效。您可以随时访问产品地址并查阅最新版许可条款,在更新生效后您继续使用本产品则被视作您已接受了新的条款。
|
||||||
|
|
||||||
|
七、 协议终止
|
||||||
|
1. 您一旦开始复制、下载、安装或者使用本产品,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的许可权力同时,也受到相关的约束和限制,本协议许可范围以外的行为,将直接违反本协议并构成侵权。
|
||||||
|
2. 一旦您违反本协议的条款,BladeX团队随时可能终止本协议、收回许可和授权,并要求您承担相应法律和经济责任。
|
||||||
43
README.md
|
|
@ -0,0 +1,43 @@
|
||||||
|
## 版权声明
|
||||||
|
* BladeX是一个商业化软件,系列产品知识产权归**上海布雷德网络科技**独立所有
|
||||||
|
* 您一旦开始复制、下载、安装或者使用本产品,即被视为完全理解并接受本协议的各项条款
|
||||||
|
* 更多详情请看:[BladeX商业授权许可协议](/LICENSE)
|
||||||
|
|
||||||
|
## 答疑流程
|
||||||
|
>1. 遇到问题或Bug
|
||||||
|
>2. 业务型问题打断点调试尝试找出问题所在
|
||||||
|
>3. 系统型问题通过百度、谷歌、社区查找解决方案
|
||||||
|
>4. 未解决问题则进入技术社区进行发帖提问:[https://sns.bladex.vip/](https://sns.bladex.vip/)
|
||||||
|
>5. 将帖子地址发至商业群,特别简单三言两语就能描述清楚的也可在答疑时间内发至商业群提问
|
||||||
|
>6. 发帖的时候一定要描述清楚,详细描述遇到问题的**重现步骤**、**报错详细信息**、**相关代码与逻辑**、**使用软件版本**以及**操作系统版本**,否则随意发帖提问将会提高我们的答疑难度。
|
||||||
|
|
||||||
|
## 答疑时间
|
||||||
|
* 工作日:9:00 ~ 17:00 提供答疑,周末、节假日休息,暂停答疑
|
||||||
|
* 请勿**私聊提问**,以免被其他用户的消息覆盖从而无法获得答疑
|
||||||
|
* 答疑时间外遇到问题可以将问题发帖至[技术社区](https://sns.bladex.vip/),我们后续会逐个回复
|
||||||
|
|
||||||
|
## 授权范围
|
||||||
|
* 专业版:只可用于**个人学习**及**个人私活**项目,不可用于公司或团队,不可泄露给任何第三方
|
||||||
|
* 企业版:可用于**企业名下**的任何项目,企业版员工在**未购买**专业版授权前,只授权开发**所在授权企业名下**的项目,**不得将BladeX用于个人私活**
|
||||||
|
* 共同遵守:若甲方需要您提供项目源码,则需代为甲方购买BladeX企业授权,甲方购买后续的所有项目都无需再次购买授权
|
||||||
|
|
||||||
|
## 商用权益
|
||||||
|
* ✔️ 遵守[商业协议](/LICENSE)的前提下,将BladeX系列产品用于授权范围内的商用项目,并上线运营
|
||||||
|
* ✔️ 遵守[商业协议](/LICENSE)的前提下,不限制项目数,不限制服务器数
|
||||||
|
* ✔️ 遵守[商业协议](/LICENSE)的前提下,将自行编写的业务代码申请软件著作权
|
||||||
|
|
||||||
|
## 何为侵权
|
||||||
|
* ❌ 不遵守商业协议,私自销售商业源码
|
||||||
|
* ❌ 以任何理由将BladeX源码用于申请软件著作权
|
||||||
|
* ❌ 将商业源码以任何途径任何理由泄露给未授权的单位或个人
|
||||||
|
* ❌ 开发完毕项目,没有为甲方购买企业授权,向甲方提供了BladeX代码
|
||||||
|
* ❌ 基于BladeX拓展研发与BladeX有竞争关系的衍生框架,并将其开源或销售
|
||||||
|
|
||||||
|
## 侵权后果
|
||||||
|
* 情节较轻:第一次发现警告处理
|
||||||
|
* 情节较重:封禁账号,踢出商业群,并保留追究法律责任的权利
|
||||||
|
* 情节严重:与本地律师事务所合作,以公司名义起诉侵犯计算机软件著作权
|
||||||
|
|
||||||
|
## 举报有奖
|
||||||
|
* 向官方提供有用线索并成功捣毁盗版个人或窝点,将会看成果给予 500~10000 不等的现金奖励
|
||||||
|
* 官方唯一指定QQ:1272154962
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
const captcha = (data) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-auth/oauth/captcha',
|
||||||
|
method: 'GET',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
captcha,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const login = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-auth/oauth/token',
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
// 获取部门数据
|
||||||
|
export function fakePosition() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const detail = {
|
||||||
|
position: "研发部",
|
||||||
|
positionArr: ['研发部', '产品部']
|
||||||
|
}
|
||||||
|
resolute(detail);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公告数据
|
||||||
|
export function fakeBannerList() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const list = [{
|
||||||
|
id: '1',
|
||||||
|
img: '/static/images/home/banner1.png',
|
||||||
|
url: 'https://bladex.vip'
|
||||||
|
}, {
|
||||||
|
id: '2',
|
||||||
|
img: '/static/images/home/banner2.png',
|
||||||
|
url: 'https://bladex.vip'
|
||||||
|
}, {
|
||||||
|
id: '3',
|
||||||
|
img: '/static/images/home/banner3.png',
|
||||||
|
url: 'https://sns.bladex.vip'
|
||||||
|
}];
|
||||||
|
resolute(list);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取公告数据
|
||||||
|
export function fakeNoticeList() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const list = [{
|
||||||
|
id: '1',
|
||||||
|
img: '/static/images/home/focus.png',
|
||||||
|
title: '天舟五号创造多个航天新纪录'
|
||||||
|
}, {
|
||||||
|
id: '2',
|
||||||
|
img: '/static/images/home/service.png',
|
||||||
|
title: '全国累计报告接种新冠疫苗超9亿剂次'
|
||||||
|
}];
|
||||||
|
resolute(list);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取顶部按钮数据
|
||||||
|
export function fakeNavButton() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const list = [{
|
||||||
|
name: '公积金',
|
||||||
|
img: '/static/images/home/n1.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '社保',
|
||||||
|
img: '/static/images/home/n2.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '医保',
|
||||||
|
img: '/static/images/home/n3.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '企业',
|
||||||
|
img: '/static/images/home/n4.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '教育',
|
||||||
|
img: '/static/images/home/n5.png',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
];
|
||||||
|
resolute(list);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务按钮数据
|
||||||
|
export function fakeServiceButton() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const list = [{
|
||||||
|
name: '工作流',
|
||||||
|
img: '/static/images/home/s1.png',
|
||||||
|
url: '/pages/plugin/workflow/pages/workbench/index'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '工商年报',
|
||||||
|
img: '/static/images/home/s2.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '税务登记',
|
||||||
|
img: '/static/images/home/s3.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '健康码',
|
||||||
|
img: '/static/images/home/s4.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '便民服务',
|
||||||
|
img: '/static/images/home/s5.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '通办大厅',
|
||||||
|
img: '/static/images/home/s6.png',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '智能问答',
|
||||||
|
img: '/static/images/home/s7.png',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
];
|
||||||
|
resolute(list);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
// 获取服务数据
|
||||||
|
export function fakeSubscribeList() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const list = [{
|
||||||
|
img: '/static/images/service/s1.png',
|
||||||
|
name: '违章查询',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s2.png',
|
||||||
|
name: '限行信息',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s3.png',
|
||||||
|
name: '油价查询',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s4.png',
|
||||||
|
name: '消费记录',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s5.png',
|
||||||
|
name: '保养记录',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s6.png',
|
||||||
|
name: '油耗记录',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s7.png',
|
||||||
|
name: '周边查询',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/s8.png',
|
||||||
|
name: '教育咨询',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
];
|
||||||
|
resolute(list);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fakeServiceList() {
|
||||||
|
return new Promise((resolute, reject) => {
|
||||||
|
try {
|
||||||
|
const list = [{
|
||||||
|
name: '交通出行',
|
||||||
|
list: [{
|
||||||
|
img: '/static/images/service/t1.png',
|
||||||
|
name: '地铁',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t2.png',
|
||||||
|
name: '公交',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t3.png',
|
||||||
|
name: '自驾',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t4.png',
|
||||||
|
name: '飞机',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t5.png',
|
||||||
|
name: '动车',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t6.png',
|
||||||
|
name: '火车',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t7.png',
|
||||||
|
name: '摩托车',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/t8.png',
|
||||||
|
name: '自行车',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '社会保险',
|
||||||
|
list: [{
|
||||||
|
img: '/static/images/service/b1.png',
|
||||||
|
name: '人身保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b2.png',
|
||||||
|
name: '财产保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b3.png',
|
||||||
|
name: '火灾保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b4.png',
|
||||||
|
name: '运输保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b5.png',
|
||||||
|
name: '工程保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b6.png',
|
||||||
|
name: '盗窃保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b7.png',
|
||||||
|
name: '农业保险',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: '/static/images/service/b8.png',
|
||||||
|
name: '信用保险',
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
resolute(list);
|
||||||
|
} catch (e) {
|
||||||
|
//模拟接口请求失败
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 获取通知公告列表
|
||||||
|
export const getList = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-desk/notice/list',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (ids) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-desk/notice/remove',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
ids,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const add = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-desk/notice/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const update = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-desk/notice/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取部门列表
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deptList = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dept/list-page',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取事项列表
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const itemList = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-biz/item/list',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约须知
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const noticeData = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-noticeinfo/noticeInfo/list',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可用日历
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const availableDate = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-bookingdate/bookingDate/available-week-dates',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户信息
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getUserInfo = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/user/info',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交预约
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const submit = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-biz/booking/submit-booking',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询我的预约
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const myReserve = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-biz/booking/list',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消预约
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const cancel = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-biz/booking/cancel',
|
||||||
|
method: 'POST',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getDetail = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-biz/booking/detail',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否无感取号成功
|
||||||
|
* @param {*} params
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getIsSuccessTicket = params => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-onlineticket/onlineTicket/getByYyNo',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
...params
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 部门管理
|
||||||
|
export const getList = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dept/lazy-list',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export const deptTree = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dept/tree',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (ids) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dept/remove',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
ids,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const add = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dept/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const update = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dept/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
//
|
||||||
|
export const dictionary = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/dictionary',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const parentList = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/parent-list',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (ids) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/remove',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
ids,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const add = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const update = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const dictTree = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/tree?code=DICT',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const child = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/dict/child-list',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 部门管理
|
||||||
|
export const getList = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/post/list',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (ids) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/post/remove',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
ids,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const add = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/post/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const update = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/post/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 角色管理
|
||||||
|
export const getList = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/role/list',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const remove = (ids) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/role/remove',
|
||||||
|
method: 'post',
|
||||||
|
params: {
|
||||||
|
ids,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const add = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/role/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const update = (row) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/role/submit',
|
||||||
|
method: 'post',
|
||||||
|
data: row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const roleTree = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/role/tree-by-id',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const menuTree = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/menu/grant-tree',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const menuTreeKey = (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/menu/role-tree-keys',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const grant = (data) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/role/grant',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 租户
|
||||||
|
export const tenantSelect= (params) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/tenant/select',
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
|
||||||
|
// 获取token
|
||||||
|
const token = (tenantId, username, password, type) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-auth/oauth/token',
|
||||||
|
method: 'POST',
|
||||||
|
header: {
|
||||||
|
'Tenant-Id': tenantId
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
tenantId,
|
||||||
|
username,
|
||||||
|
mmword: password,
|
||||||
|
grant_type: "password",
|
||||||
|
scope: "all",
|
||||||
|
type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const refreshToken = (refresh_token, tenantId) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-auth/oauth/token',
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Tenant-Id': tenantId
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
tenantId,
|
||||||
|
refresh_token,
|
||||||
|
grant_type: "refresh_token",
|
||||||
|
scope: "all",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
const userInfo = () => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/user/info',
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
export const getUser = (id) => {
|
||||||
|
return http.request({
|
||||||
|
url: '/api/blade-system/user/detail',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
token,
|
||||||
|
userInfo,
|
||||||
|
refreshToken
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 全局变量配置
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
// 应用名
|
||||||
|
name: 'Rider',
|
||||||
|
// 应用logo,支持本地路径和网络路径
|
||||||
|
logo: '/static/images/logo.png',
|
||||||
|
// 版本号
|
||||||
|
version: '2.1.0',
|
||||||
|
// 开发环境接口Url
|
||||||
|
// #ifdef H5
|
||||||
|
devUrl: '',
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
devUrl: 'http://127.0.0.1',
|
||||||
|
// #endif
|
||||||
|
// 线上环境接口Url
|
||||||
|
prodUrl: '/housingAssuranceBookingMobile',
|
||||||
|
// 后端数据的接收方式application/json;charset=UTF-8或者application/x-www-form-urlencoded;charset=UTF-8
|
||||||
|
contentType: 'application/json;charset=UTF-8',
|
||||||
|
// 后端返回状态码
|
||||||
|
codeName: 'code',
|
||||||
|
// 操作正常code
|
||||||
|
successCode: 200,
|
||||||
|
// 登录失效code
|
||||||
|
invalidCode: 401,
|
||||||
|
// 客户端ID
|
||||||
|
clientId: 'rider',
|
||||||
|
// 客户端密钥
|
||||||
|
clientSecret: 'rider_secret',
|
||||||
|
// token过期时间
|
||||||
|
tokenTime: 3000,
|
||||||
|
// 国密sm2公钥使用后端工程 @org.springblade.test.Sm2KeyGenerator 获取
|
||||||
|
publicKey: '049bb83747f21a4f6ecfd4984e02b611f6bf8180b49818edb7349632416aa65a2e267ae14fcac6f82054888774262244424ab629357a7d98cdd23f4c4eee9f2269'
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
<template>
|
||||||
|
<view class="nav-wrap">
|
||||||
|
<view class="nav-title">
|
||||||
|
<image class="logo" src="/static/images/logo.png" mode="widthFix"></image>
|
||||||
|
<view class="nav-info">
|
||||||
|
<view class="nav-title__text">
|
||||||
|
{{title}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="nav-desc">
|
||||||
|
{{desc}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
desc: String,
|
||||||
|
title: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-wrap {
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 15px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-info {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title__text {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: flex;
|
||||||
|
/* #endif */
|
||||||
|
color: $u-main-color;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 100px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
height: auto;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-slogan {
|
||||||
|
color: $u-tips-color;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-desc {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
<template>
|
||||||
|
<picker
|
||||||
|
mode="multiSelector"
|
||||||
|
:value="multiIndex"
|
||||||
|
:range="multiArray"
|
||||||
|
@change="handleValueChange"
|
||||||
|
@columnchange="handleColumnChange"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</picker>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const CHINA_REGIONS = require('./regions.json');
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
defaultRegions: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultRegionCode: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
defaultRegion: [String, Array],
|
||||||
|
value: [String, Array]
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cityArr: CHINA_REGIONS[0].childs,
|
||||||
|
districtArr: CHINA_REGIONS[0].childs[0].childs,
|
||||||
|
multiIndex: [0, 0, 0],
|
||||||
|
isInitMultiArray: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
defaultRegion: {
|
||||||
|
handler(region, oldRegion) {
|
||||||
|
if (Array.isArray(region)) {
|
||||||
|
// 避免传的是字面量的时候重复触发
|
||||||
|
oldRegion = oldRegion || [];
|
||||||
|
if (region.join('') !== oldRegion.join('')) {
|
||||||
|
this.handleDefaultRegion(region);
|
||||||
|
}
|
||||||
|
} else if (region && region.length == 6) {
|
||||||
|
this.handleDefaultRegion(region);
|
||||||
|
} else {
|
||||||
|
console.warn('defaultRegion非有效格式');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
multiArray() {
|
||||||
|
return this.pickedArr.map(arr => arr.map(item => item.name));
|
||||||
|
},
|
||||||
|
pickedArr() {
|
||||||
|
// 进行初始化
|
||||||
|
if (this.isInitMultiArray) {
|
||||||
|
return [
|
||||||
|
CHINA_REGIONS,
|
||||||
|
CHINA_REGIONS[0].childs,
|
||||||
|
CHINA_REGIONS[0].childs[0].childs
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [CHINA_REGIONS, this.cityArr, this.districtArr];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleColumnChange(e) {
|
||||||
|
// console.log(e);
|
||||||
|
this.isInitMultiArray = false;
|
||||||
|
const that = this;
|
||||||
|
let col = e.detail.column;
|
||||||
|
let row = e.detail.value;
|
||||||
|
that.multiIndex[col] = row;
|
||||||
|
try {
|
||||||
|
switch (col) {
|
||||||
|
case 0:
|
||||||
|
if (CHINA_REGIONS[that.multiIndex[0]].childs.length == 0) {
|
||||||
|
that.cityArr = that.districtArr = [
|
||||||
|
CHINA_REGIONS[that.multiIndex[0]]
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
that.cityArr = CHINA_REGIONS[that.multiIndex[0]].childs;
|
||||||
|
that.districtArr =
|
||||||
|
CHINA_REGIONS[that.multiIndex[0]].childs[
|
||||||
|
that.multiIndex[1]
|
||||||
|
].childs;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
that.districtArr =
|
||||||
|
CHINA_REGIONS[that.multiIndex[0]].childs[
|
||||||
|
that.multiIndex[1]
|
||||||
|
].childs;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// console.log(e);
|
||||||
|
that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[0].childs;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleValueChange(e) {
|
||||||
|
// 结构赋值
|
||||||
|
let [index0, index1, index2] = e.detail.value;
|
||||||
|
let [arr0, arr1, arr2] = this.pickedArr;
|
||||||
|
let address = [arr0[index0], arr1[index1], arr2[index2]];
|
||||||
|
// console.log(address);
|
||||||
|
this.$emit('getRegion', address);
|
||||||
|
this.$emit(
|
||||||
|
'input',
|
||||||
|
`${address[0].name}${address[1].name}${address[2].name}`
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleDefaultRegion(region) {
|
||||||
|
const isCode = !Array.isArray(region);
|
||||||
|
this.isInitMultiArray = false;
|
||||||
|
let children = CHINA_REGIONS;
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
for (let j = 0; j < children.length; j++) {
|
||||||
|
let condition = isCode
|
||||||
|
? children[j].code == region.slice(0, (i + 1) * 2)
|
||||||
|
: children[j].name.includes(region[i]);
|
||||||
|
if (condition) {
|
||||||
|
// 匹配成功进行赋值
|
||||||
|
// console.log(i,j,children.length-1);
|
||||||
|
children = children[j].childs;
|
||||||
|
if (i == 0) {
|
||||||
|
this.cityArr = children;
|
||||||
|
} else if (i == 1) {
|
||||||
|
this.districtArr = children;
|
||||||
|
}
|
||||||
|
this.$set(this.multiIndex, i, j);
|
||||||
|
// console.log(this.multiIndex);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// 首次匹配失败就用默认的初始化
|
||||||
|
// console.log(i,j,children.length-1);
|
||||||
|
if (i == 0 && j == children.length - 1) {
|
||||||
|
this.isInitMultiArray = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
<template>
|
||||||
|
<view class="">
|
||||||
|
<rider-swipe-action :actions="option.actions" @click="onActionClick($event, nodeIndex, list)">
|
||||||
|
<template v-slot:content>
|
||||||
|
<view class="crud flex flex-c">
|
||||||
|
<view class="crud-checkbox">
|
||||||
|
<checkbox-group @change="e => onChecked(e, node.id)" v-if="checkShow">
|
||||||
|
<label>
|
||||||
|
<checkbox
|
||||||
|
style="transform: scale(0.7)"
|
||||||
|
:value="node.id"
|
||||||
|
:checked="checkList.includes(node.id)"
|
||||||
|
class="curdCheck"
|
||||||
|
></checkbox>
|
||||||
|
</label>
|
||||||
|
</checkbox-group>
|
||||||
|
</view>
|
||||||
|
<view class="flex-one" @click.stop="onActionClick({ index: -1 }, nodeIndex, list)">
|
||||||
|
<view v-for="(col, i) in option.column" :key="i" class="crud-row flex">
|
||||||
|
<view class="crud-row-label">{{ col.label }}:</view>
|
||||||
|
<view class="crud-row-value">{{ node[col.prop] }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<block v-if="node.hasChildren || (node.children && node.children.length > 0)">
|
||||||
|
<view class="crud-child" @click="onToggle(node, nodeIndex)">
|
||||||
|
{{ !collapsed ? '查看下级' : '收起' }}
|
||||||
|
<u-icon :name="`arrow-${!collapsed ? 'down' : 'up'}`"></u-icon>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</template>
|
||||||
|
</rider-swipe-action>
|
||||||
|
<!-- 下级 -->
|
||||||
|
<template v-if="node.hasChildren || (node.children && node.children.length > 0)">
|
||||||
|
<!-- <block v-if="collapsed">
|
||||||
|
<view class="" v-for="(item, index) in node.children" :key="index">
|
||||||
|
<crud-item :ref="`crud-itemc${index}`" :node="item" :list="node.children" :option="option" :checkShow="checkShow" :nodeIndex="index" :checkList="checkList"></crud-item>
|
||||||
|
</view>
|
||||||
|
</block> -->
|
||||||
|
<u-popup v-model="collapsed" mode="bottom" closeable :mask-close-able="false" :z-index="zIndex">
|
||||||
|
<view class="form-head"><u-section title="查看下级" :right="false" line-color="#5f88ff"></u-section></view>
|
||||||
|
<scroll-view scroll-y="true" style="height: 75vh; background: #f5f5f5">
|
||||||
|
<crud-item
|
||||||
|
v-for="(item, index) in node.children"
|
||||||
|
:key="index"
|
||||||
|
:ref="`crud-item${index}`"
|
||||||
|
:node="item"
|
||||||
|
:list="node.children"
|
||||||
|
:option="option"
|
||||||
|
:checkShow="checkShow"
|
||||||
|
:nodeIndex="index"
|
||||||
|
:checkList="checkList"
|
||||||
|
:random-num="randomNum"
|
||||||
|
:z-index="zIndex + 1"
|
||||||
|
></crud-item>
|
||||||
|
</scroll-view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderSwipeAction from '../swipe-action/index'
|
||||||
|
// #ifdef MP
|
||||||
|
import crudItem from '@/components/rider-crud/components/crud-item/index'
|
||||||
|
// #endif
|
||||||
|
export default {
|
||||||
|
name: 'crud-item',
|
||||||
|
components: {
|
||||||
|
riderSwipeAction,
|
||||||
|
// #ifndef MP
|
||||||
|
crudItem: () => import('@/components/rider-crud/components/crud-item/index'),
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP
|
||||||
|
crudItem
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
// 节点数据
|
||||||
|
node: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
},
|
||||||
|
list: Array,
|
||||||
|
// 节点角标
|
||||||
|
nodeIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 配置
|
||||||
|
option: {
|
||||||
|
type: Object,
|
||||||
|
default: {
|
||||||
|
column: [],
|
||||||
|
manageSwitch: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkList: Array,
|
||||||
|
checkShow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
randomNum: Number,
|
||||||
|
zIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 10075
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
collapsed: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setLazyLoad(func) {
|
||||||
|
this.option.lazyLoad = func
|
||||||
|
},
|
||||||
|
onActionClick({ index }, i, list) {
|
||||||
|
uni.$emit(`action${this.randomNum}`, { index }, i, list)
|
||||||
|
},
|
||||||
|
onChecked(e, id) {
|
||||||
|
uni.$emit(`checked${this.randomNum}`, e, id)
|
||||||
|
},
|
||||||
|
onToggle(item, index) {
|
||||||
|
if (item.hasChildren && this.collapsed == false) {
|
||||||
|
if (!item.children || item.children.length == 0) {
|
||||||
|
// #ifdef MP
|
||||||
|
uni.showToast({
|
||||||
|
title: '小程序暂不支持懒加载查看下级',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
// #endif
|
||||||
|
if (typeof this.option.lazyLoad == 'function') {
|
||||||
|
const cb = list => {
|
||||||
|
this.$set(item, 'children', list)
|
||||||
|
this.collapsed = true
|
||||||
|
}
|
||||||
|
this.option.lazyLoad(item, index, cb)
|
||||||
|
}
|
||||||
|
} else this.collapsed = true
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.node.children)
|
||||||
|
this.node.children.forEach((l, i) => {
|
||||||
|
this.$refs[`crud-item${i}`][0].setLazyLoad(this.option.lazyLoad)
|
||||||
|
})
|
||||||
|
}, 100)
|
||||||
|
} else {
|
||||||
|
this.collapsed = !this.collapsed
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.collapsed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-c {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-one {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-head {
|
||||||
|
padding: 36rpx 30rpx;
|
||||||
|
border-bottom: 2rpx dashed #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crud {
|
||||||
|
background: #fff;
|
||||||
|
padding: 26rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
|
||||||
|
.crud-row + .crud-row {
|
||||||
|
margin-top: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-child {
|
||||||
|
color: #5f88ff;
|
||||||
|
font-size: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
border-top: 2rpx dashed #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-row {
|
||||||
|
&-label {
|
||||||
|
color: #999;
|
||||||
|
font-size: 28rpx;
|
||||||
|
margin-right: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-value {
|
||||||
|
flex: 1;
|
||||||
|
color: #565656;
|
||||||
|
font-size: 28rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// 以下项目可以删减或更换顺序,但不能添加或更改名字
|
||||||
|
export default {
|
||||||
|
// 普通标签的菜单项
|
||||||
|
node: ['大小', '斜体', '粗体', '下划线', '居中', '缩进', '上移', '下移', '删除'],
|
||||||
|
// 图片的菜单项
|
||||||
|
img: ['换图', '宽度', '超链接', '预览图', '禁用预览', '上移', '下移', '删除'],
|
||||||
|
// 链接的菜单项
|
||||||
|
link: ['更换链接', '上移', '下移', '删除'],
|
||||||
|
// 音视频的菜单项
|
||||||
|
media: ['封面', '循环', '自动播放', '上移', '下移', '删除']
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,532 @@
|
||||||
|
/**
|
||||||
|
* @fileoverview editable 插件
|
||||||
|
*/
|
||||||
|
import config from './config'
|
||||||
|
import Parser from '../parser'
|
||||||
|
|
||||||
|
function Editable (vm) {
|
||||||
|
this.vm = vm
|
||||||
|
this.editHistory = [] // 历史记录
|
||||||
|
this.editI = -1 // 历史记录指针
|
||||||
|
vm._mask = [] // 蒙版被点击时进行的操作
|
||||||
|
|
||||||
|
vm._setData = function (path, val) {
|
||||||
|
const paths = path.split('.')
|
||||||
|
let target = vm
|
||||||
|
for (let i = 0; i < paths.length - 1; i++) {
|
||||||
|
target = target[paths[i]]
|
||||||
|
}
|
||||||
|
vm.$set(target, paths.pop(), val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 移动历史记录指针
|
||||||
|
* @param {Number} num 移动距离
|
||||||
|
*/
|
||||||
|
const move = num => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const item = this.editHistory[this.editI + num]
|
||||||
|
if (item) {
|
||||||
|
this.editI += num
|
||||||
|
vm._setData(item.key, item.value)
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
vm.undo = () => move(-1) // 撤销
|
||||||
|
vm.redo = () => move(1) // 重做
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 更新记录
|
||||||
|
* @param {String} path 更新内容路径
|
||||||
|
* @param {*} oldVal 旧值
|
||||||
|
* @param {*} newVal 新值
|
||||||
|
* @param {Boolean} set 是否更新到视图
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
vm._editVal = (path, oldVal, newVal, set) => {
|
||||||
|
// 当前指针后的内容去除
|
||||||
|
while (this.editI < this.editHistory.length - 1) {
|
||||||
|
this.editHistory.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最多存储 30 条操作记录
|
||||||
|
while (this.editHistory.length > 30) {
|
||||||
|
this.editHistory.pop()
|
||||||
|
this.editI--
|
||||||
|
}
|
||||||
|
|
||||||
|
const last = this.editHistory[this.editHistory.length - 1]
|
||||||
|
if (!last || last.key !== path) {
|
||||||
|
if (last) {
|
||||||
|
// 去掉上一次的新值
|
||||||
|
this.editHistory.pop()
|
||||||
|
this.editI--
|
||||||
|
}
|
||||||
|
// 存入这一次的旧值
|
||||||
|
this.editHistory.push({
|
||||||
|
key: path,
|
||||||
|
value: oldVal
|
||||||
|
})
|
||||||
|
this.editI++
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存入本次的新值
|
||||||
|
this.editHistory.push({
|
||||||
|
key: path,
|
||||||
|
value: newVal
|
||||||
|
})
|
||||||
|
this.editI++
|
||||||
|
|
||||||
|
// 更新到视图
|
||||||
|
if (set) {
|
||||||
|
vm._setData(path, newVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取菜单项
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
vm._getItem = function (node, up, down) {
|
||||||
|
let items
|
||||||
|
let i
|
||||||
|
if (node.name === 'img') {
|
||||||
|
items = config.img.slice(0)
|
||||||
|
if (!vm.getSrc) {
|
||||||
|
i = items.indexOf('换图')
|
||||||
|
if (i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
i = items.indexOf('超链接')
|
||||||
|
if (i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
i = items.indexOf('预览图')
|
||||||
|
if (i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = items.indexOf('禁用预览')
|
||||||
|
if (i !== -1 && node.attrs.ignore) {
|
||||||
|
items[i] = '启用预览'
|
||||||
|
}
|
||||||
|
} else if (node.name === 'a') {
|
||||||
|
items = config.link.slice(0)
|
||||||
|
if (!vm.getSrc) {
|
||||||
|
i = items.indexOf('更换链接')
|
||||||
|
if (i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (node.name === 'video' || node.name === 'audio') {
|
||||||
|
items = config.media.slice(0)
|
||||||
|
i = items.indexOf('封面')
|
||||||
|
if (!vm.getSrc && i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
i = items.indexOf('循环')
|
||||||
|
if (node.attrs.loop && i !== -1) {
|
||||||
|
items[i] = '不循环'
|
||||||
|
}
|
||||||
|
i = items.indexOf('自动播放')
|
||||||
|
if (node.attrs.autoplay && i !== -1) {
|
||||||
|
items[i] = '不自动播放'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items = config.node.slice(0)
|
||||||
|
}
|
||||||
|
if (!up) {
|
||||||
|
i = items.indexOf('上移')
|
||||||
|
if (i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!down) {
|
||||||
|
i = items.indexOf('下移')
|
||||||
|
if (i !== -1) {
|
||||||
|
items.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 显示 tooltip
|
||||||
|
* @param {object} obj
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
vm._tooltip = function (obj) {
|
||||||
|
vm.$set(vm, 'tooltip', {
|
||||||
|
top: obj.top,
|
||||||
|
items: obj.items
|
||||||
|
})
|
||||||
|
vm._tooltipcb = obj.success
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 显示滚动条
|
||||||
|
* @param {object} obj
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
vm._slider = function (obj) {
|
||||||
|
vm.$set(vm, 'slider', {
|
||||||
|
min: obj.min,
|
||||||
|
max: obj.max,
|
||||||
|
value: obj.value,
|
||||||
|
top: obj.top
|
||||||
|
})
|
||||||
|
vm._slideringcb = obj.changing
|
||||||
|
vm._slidercb = obj.change
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 点击蒙版
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
vm._maskTap = function () {
|
||||||
|
// 隐藏所有悬浮窗
|
||||||
|
while (vm._mask.length) {
|
||||||
|
(vm._mask.pop())()
|
||||||
|
}
|
||||||
|
if (vm.tooltip) {
|
||||||
|
vm.$set(vm, 'tooltip', null)
|
||||||
|
}
|
||||||
|
if (vm.slider) {
|
||||||
|
vm.$set(vm, 'slider', null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 插入节点
|
||||||
|
* @param {Object} node
|
||||||
|
*/
|
||||||
|
function insert (node) {
|
||||||
|
if (vm._edit) {
|
||||||
|
vm._edit.insert(node)
|
||||||
|
} else {
|
||||||
|
const nodes = vm.nodes.slice(0)
|
||||||
|
nodes.push(node)
|
||||||
|
vm._editVal('nodes', vm.nodes, nodes, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入指定 html 内容
|
||||||
|
* @param {String} html 内容
|
||||||
|
*/
|
||||||
|
vm.insertHtml = html => {
|
||||||
|
this.inserting = true
|
||||||
|
const arr = new Parser(vm).parse(html)
|
||||||
|
this.inserting = undefined
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
insert(arr[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入图片
|
||||||
|
*/
|
||||||
|
vm.insertImg = function () {
|
||||||
|
vm.getSrc && vm.getSrc('img').then(src => {
|
||||||
|
if (typeof src === 'string') {
|
||||||
|
src = [src]
|
||||||
|
}
|
||||||
|
const parser = new Parser(vm)
|
||||||
|
for (let i = 0; i < src.length; i++) {
|
||||||
|
insert({
|
||||||
|
name: 'img',
|
||||||
|
attrs: {
|
||||||
|
src: parser.getUrl(src[i])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入一个链接
|
||||||
|
*/
|
||||||
|
vm.insertLink = function () {
|
||||||
|
vm.getSrc && vm.getSrc('link').then(url => {
|
||||||
|
insert({
|
||||||
|
name: 'a',
|
||||||
|
attrs: {
|
||||||
|
href: url
|
||||||
|
},
|
||||||
|
children: [{
|
||||||
|
type: 'text',
|
||||||
|
text: url
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入一个表格
|
||||||
|
* @param {Number} rows 行数
|
||||||
|
* @param {Number} cols 列数
|
||||||
|
*/
|
||||||
|
vm.insertTable = function (rows, cols) {
|
||||||
|
const table = {
|
||||||
|
name: 'table',
|
||||||
|
attrs: {
|
||||||
|
style: 'display:table;width:100%;margin:10px 0;text-align:center;border-spacing:0;border-collapse:collapse;border:1px solid gray'
|
||||||
|
},
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
for (let i = 0; i < rows; i++) {
|
||||||
|
const tr = {
|
||||||
|
name: 'tr',
|
||||||
|
attrs: {},
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
for (let j = 0; j < cols; j++) {
|
||||||
|
tr.children.push({
|
||||||
|
name: 'td',
|
||||||
|
attrs: {
|
||||||
|
style: 'padding:2px;border:1px solid gray'
|
||||||
|
},
|
||||||
|
children: [{
|
||||||
|
type: 'text',
|
||||||
|
text: ''
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
table.children.push(tr)
|
||||||
|
}
|
||||||
|
insert(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 插入视频/音频
|
||||||
|
* @param {Object} node
|
||||||
|
*/
|
||||||
|
function insertMedia (node) {
|
||||||
|
if (typeof node.src === 'string') {
|
||||||
|
node.src = [node.src]
|
||||||
|
}
|
||||||
|
const parser = new Parser(vm)
|
||||||
|
// 拼接主域名
|
||||||
|
for (let i = 0; i < node.src.length; i++) {
|
||||||
|
node.src[i] = parser.getUrl(node.src[i])
|
||||||
|
}
|
||||||
|
insert({
|
||||||
|
name: 'div',
|
||||||
|
attrs: {
|
||||||
|
style: 'text-align:center'
|
||||||
|
},
|
||||||
|
children: [node]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入一个视频
|
||||||
|
*/
|
||||||
|
vm.insertVideo = function () {
|
||||||
|
vm.getSrc && vm.getSrc('video').then(src => {
|
||||||
|
insertMedia({
|
||||||
|
name: 'video',
|
||||||
|
attrs: {
|
||||||
|
controls: 'T'
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
|
src,
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
html: `<video src="${src}" style="width:100%;height:100%"></video>`
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入一个音频
|
||||||
|
*/
|
||||||
|
vm.insertAudio = function () {
|
||||||
|
vm.getSrc && vm.getSrc('audio').then(attrs => {
|
||||||
|
let src
|
||||||
|
if (attrs.src) {
|
||||||
|
src = attrs.src
|
||||||
|
attrs.src = undefined
|
||||||
|
} else {
|
||||||
|
src = attrs
|
||||||
|
attrs = {}
|
||||||
|
}
|
||||||
|
attrs.controls = 'T'
|
||||||
|
insertMedia({
|
||||||
|
name: 'audio',
|
||||||
|
attrs,
|
||||||
|
children: [],
|
||||||
|
src
|
||||||
|
})
|
||||||
|
}).catch(() => { })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在光标处插入一段文本
|
||||||
|
*/
|
||||||
|
vm.insertText = function () {
|
||||||
|
insert({
|
||||||
|
name: 'p',
|
||||||
|
attrs: {},
|
||||||
|
children: [{
|
||||||
|
type: 'text',
|
||||||
|
text: ''
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 清空内容
|
||||||
|
*/
|
||||||
|
vm.clear = function () {
|
||||||
|
vm._maskTap()
|
||||||
|
vm._edit = undefined
|
||||||
|
vm.$set(vm, 'nodes', [{
|
||||||
|
name: 'p',
|
||||||
|
attrs: {},
|
||||||
|
children: [{
|
||||||
|
type: 'text',
|
||||||
|
text: ''
|
||||||
|
}]
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取编辑后的 html
|
||||||
|
*/
|
||||||
|
vm.getContent = function () {
|
||||||
|
let html = '';
|
||||||
|
// 递归遍历获取
|
||||||
|
(function traversal (nodes, table) {
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
let item = nodes[i]
|
||||||
|
if (item.type === 'text') {
|
||||||
|
html += item.text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>').replace(/\xa0/g, ' ') // 编码实体
|
||||||
|
} else {
|
||||||
|
if (item.name === 'img') {
|
||||||
|
item.attrs.i = ''
|
||||||
|
// 还原被转换的 svg
|
||||||
|
if ((item.attrs.src || '').includes('data:image/svg+xml;utf8,')) {
|
||||||
|
html += item.attrs.src.substr(24).replace(/%23/g, '#').replace('<svg', '<svg style="' + (item.attrs.style || '') + '"')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if (item.name === 'video' || item.name === 'audio') {
|
||||||
|
// 还原 video 和 audio 的 source
|
||||||
|
item = JSON.parse(JSON.stringify(item))
|
||||||
|
if (item.src.length > 1) {
|
||||||
|
item.children = []
|
||||||
|
for (let j = 0; j < item.src.length; j++) {
|
||||||
|
item.children.push({
|
||||||
|
name: 'source',
|
||||||
|
attrs: {
|
||||||
|
src: item.src[j]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.attrs.src = item.src[0]
|
||||||
|
}
|
||||||
|
} else if (item.name === 'div' && (item.attrs.style || '').includes('overflow:auto') && (item.children[0] || {}).name === 'table') {
|
||||||
|
// 还原滚动层
|
||||||
|
item = item.children[0]
|
||||||
|
}
|
||||||
|
// 还原 table
|
||||||
|
if (item.name === 'table') {
|
||||||
|
item = JSON.parse(JSON.stringify(item))
|
||||||
|
table = item.attrs
|
||||||
|
if ((item.attrs.style || '').includes('display:grid')) {
|
||||||
|
item.attrs.style = item.attrs.style.split('display:grid')[0]
|
||||||
|
const children = [{
|
||||||
|
name: 'tr',
|
||||||
|
attrs: {},
|
||||||
|
children: []
|
||||||
|
}]
|
||||||
|
for (let j = 0; j < item.children.length; j++) {
|
||||||
|
item.children[j].attrs.style = item.children[j].attrs.style.replace(/grid-[^;]+;*/g, '')
|
||||||
|
if (item.children[j].r !== children.length) {
|
||||||
|
children.push({
|
||||||
|
name: 'tr',
|
||||||
|
attrs: {},
|
||||||
|
children: [item.children[j]]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
children[children.length - 1].children.push(item.children[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.children = children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += '<' + item.name
|
||||||
|
for (const attr in item.attrs) {
|
||||||
|
let val = item.attrs[attr]
|
||||||
|
if (!val) continue
|
||||||
|
if (val === 'T' || val === true) {
|
||||||
|
// bool 型省略值
|
||||||
|
html += ' ' + attr
|
||||||
|
continue
|
||||||
|
} else if (item.name[0] === 't' && attr === 'style' && table) {
|
||||||
|
// 取消为了显示 table 添加的 style
|
||||||
|
val = val.replace(/;*display:table[^;]*/, '')
|
||||||
|
if (table.border) {
|
||||||
|
val = val.replace(/border[^;]+;*/g, $ => $.includes('collapse') ? $ : '')
|
||||||
|
}
|
||||||
|
if (table.cellpadding) {
|
||||||
|
val = val.replace(/padding[^;]+;*/g, '')
|
||||||
|
}
|
||||||
|
if (!val) continue
|
||||||
|
}
|
||||||
|
html += ' ' + attr + '="' + val.replace(/"/g, '"') + '"'
|
||||||
|
}
|
||||||
|
html += '>'
|
||||||
|
if (item.children) {
|
||||||
|
traversal(item.children, table)
|
||||||
|
html += '</' + item.name + '>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(vm.nodes)
|
||||||
|
|
||||||
|
// 其他插件处理
|
||||||
|
for (let i = vm.plugins.length; i--;) {
|
||||||
|
if (vm.plugins[i].onGetContent) {
|
||||||
|
html = vm.plugins[i].onGetContent(html) || html
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Editable.prototype.onUpdate = function (content, config) {
|
||||||
|
if (this.vm.editable) {
|
||||||
|
this.vm._maskTap()
|
||||||
|
config.entities.amp = '&'
|
||||||
|
if (!this.inserting) {
|
||||||
|
this.vm._edit = undefined
|
||||||
|
if (!content) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.vm.$set(this.vm, 'nodes', [{
|
||||||
|
name: 'p',
|
||||||
|
attrs: {},
|
||||||
|
children: [{
|
||||||
|
type: 'text',
|
||||||
|
text: ''
|
||||||
|
}]
|
||||||
|
}])
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Editable.prototype.onParse = function (node) {
|
||||||
|
// 空白单元格可编辑
|
||||||
|
if (this.vm.editable && (node.name === 'td' || node.name === 'th') && !this.vm.getText(node.children)) {
|
||||||
|
node.children.push({
|
||||||
|
type: 'text',
|
||||||
|
text: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Editable
|
||||||
|
|
@ -0,0 +1,540 @@
|
||||||
|
<template>
|
||||||
|
<view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="(editable?'min-height:200px;':'')+containerStyle" @tap="_containTap">
|
||||||
|
<slot v-if="!nodes[0]" />
|
||||||
|
<!-- #ifndef APP-PLUS-NVUE -->
|
||||||
|
<node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable,editable,placeholder,'nodes']" name="span" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-PLUS-NVUE -->
|
||||||
|
<web-view ref="web" src="/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<view v-if="tooltip" class="_tooltip_contain" :style="'top:'+tooltip.top+'px'">
|
||||||
|
<view class="_tooltip">
|
||||||
|
<view v-for="(item, index) in tooltip.items" v-bind:key="index" class="_tooltip_item" :data-i="index" @tap="_tooltipTap">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="slider" class="_slider" :style="'top:'+slider.top+'px'">
|
||||||
|
<slider :value="slider.value" :min="slider.min" :max="slider.max" handle-size="14" block-size="14" show-value activeColor="white" style="padding:3px" @changing="_sliderChanging" @change="_sliderChange" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* mp-html v2.3.2
|
||||||
|
* @description 富文本组件
|
||||||
|
* @tutorial https://github.com/jin-yufeng/mp-html
|
||||||
|
* @property {String} container-style 容器的样式
|
||||||
|
* @property {String} content 用于渲染的 html 字符串
|
||||||
|
* @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
|
||||||
|
* @property {String} domain 主域名,用于拼接链接
|
||||||
|
* @property {String} error-img 图片出错时的占位图链接
|
||||||
|
* @property {Boolean} lazy-load 是否开启图片懒加载
|
||||||
|
* @property {string} loading-img 图片加载过程中的占位图链接
|
||||||
|
* @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
|
||||||
|
* @property {Boolean} preview-img 是否允许图片被点击时自动预览
|
||||||
|
* @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
|
||||||
|
* @property {Boolean | String} selectable 是否开启长按复制
|
||||||
|
* @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
|
||||||
|
* @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
|
||||||
|
* @property {Object} tag-style 标签的默认样式
|
||||||
|
* @property {Boolean | Number} use-anchor 是否使用锚点链接
|
||||||
|
* @event {Function} load dom 结构加载完毕时触发
|
||||||
|
* @event {Function} ready 所有图片加载完毕时触发
|
||||||
|
* @event {Function} imgtap 图片被点击时触发
|
||||||
|
* @event {Function} linktap 链接被点击时触发
|
||||||
|
* @event {Function} play 音视频播放时触发
|
||||||
|
* @event {Function} error 媒体加载出错时触发
|
||||||
|
*/
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
import node from './node/node'
|
||||||
|
// #endif
|
||||||
|
import Parser from './parser'
|
||||||
|
import editable from './editable/index.js'
|
||||||
|
const plugins=[editable,]
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
const dom = weex.requireModule('dom')
|
||||||
|
// #endif
|
||||||
|
export default {
|
||||||
|
name: 'mp-html',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tooltip: null,
|
||||||
|
slider: null,
|
||||||
|
nodes: [],
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
height: 3
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
editable: Boolean,
|
||||||
|
placeholder: String,
|
||||||
|
containerStyle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
copyLink: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
domain: String,
|
||||||
|
errorImg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
lazyLoad: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
loadingImg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
pauseVideo: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
previewImg: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
scrollTable: [Boolean, String],
|
||||||
|
selectable: [Boolean, String],
|
||||||
|
setTitle: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showImgMenu: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
tagStyle: Object,
|
||||||
|
useAnchor: [Boolean, Number]
|
||||||
|
},
|
||||||
|
// #ifdef VUE3
|
||||||
|
emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
components: {
|
||||||
|
node
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
watch: {
|
||||||
|
editable(val) {
|
||||||
|
this.setContent(val ? this.content : this.getContent())
|
||||||
|
if (!val)
|
||||||
|
this._maskTap()
|
||||||
|
},
|
||||||
|
content (content) {
|
||||||
|
this.setContent(content)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.plugins = []
|
||||||
|
for (let i = plugins.length; i--;) {
|
||||||
|
this.plugins.push(new plugins[i](this))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if ((this.content || this.editable) && !this.nodes.length) {
|
||||||
|
this.setContent(this.content)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this._hook('onDetached')
|
||||||
|
clearInterval(this._timer)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
_containTap() {
|
||||||
|
if (!this._lock && !this.slider) {
|
||||||
|
this._edit = undefined
|
||||||
|
this._maskTap()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_tooltipTap(e) {
|
||||||
|
this._tooltipcb(e.currentTarget.dataset.i)
|
||||||
|
this.$set(this, 'tooltip', null)
|
||||||
|
},
|
||||||
|
_sliderChanging(e) {
|
||||||
|
this._slideringcb(e.detail.value)
|
||||||
|
},
|
||||||
|
_sliderChange(e) {
|
||||||
|
this._slidercb(e.detail.value)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @description 将锚点跳转的范围限定在一个 scroll-view 内
|
||||||
|
* @param {Object} page scroll-view 所在页面的示例
|
||||||
|
* @param {String} selector scroll-view 的选择器
|
||||||
|
* @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
|
||||||
|
*/
|
||||||
|
in (page, selector, scrollTop) {
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
if (page && selector && scrollTop) {
|
||||||
|
this._in = {
|
||||||
|
page,
|
||||||
|
selector,
|
||||||
|
scrollTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 锚点跳转
|
||||||
|
* @param {String} id 要跳转的锚点 id
|
||||||
|
* @param {Number} offset 跳转位置的偏移量
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
navigateTo (id, offset) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!this.useAnchor) {
|
||||||
|
reject(Error('Anchor is disabled'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset = offset || parseInt(this.useAnchor) || 0
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
if (!id) {
|
||||||
|
dom.scrollToElement(this.$refs.web, {
|
||||||
|
offset
|
||||||
|
})
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
this._navigateTo = {
|
||||||
|
resolve,
|
||||||
|
reject,
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
let deep = ' '
|
||||||
|
// #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
|
||||||
|
deep = '>>>'
|
||||||
|
// #endif
|
||||||
|
const selector = uni.createSelectorQuery()
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
|
.in(this._in ? this._in.page : this)
|
||||||
|
// #endif
|
||||||
|
.select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
|
||||||
|
if (this._in) {
|
||||||
|
selector.select(this._in.selector).scrollOffset()
|
||||||
|
.select(this._in.selector).boundingClientRect()
|
||||||
|
} else {
|
||||||
|
// 获取 scroll-view 的位置和滚动距离
|
||||||
|
selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
|
||||||
|
}
|
||||||
|
selector.exec(res => {
|
||||||
|
if (!res[0]) {
|
||||||
|
reject(Error('Label not found'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
|
||||||
|
if (this._in) {
|
||||||
|
// scroll-view 跳转
|
||||||
|
this._in.page[this._in.scrollTop] = scrollTop
|
||||||
|
} else {
|
||||||
|
// 页面跳转
|
||||||
|
uni.pageScrollTo({
|
||||||
|
scrollTop,
|
||||||
|
duration: 300
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取文本内容
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getText (nodes) {
|
||||||
|
let text = '';
|
||||||
|
(function traversal (nodes) {
|
||||||
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
|
const node = nodes[i]
|
||||||
|
if (node.type === 'text') {
|
||||||
|
text += node.text.replace(/&/g, '&')
|
||||||
|
} else if (node.name === 'br') {
|
||||||
|
text += '\n'
|
||||||
|
} else {
|
||||||
|
// 块级标签前后加换行
|
||||||
|
const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
|
||||||
|
if (isBlock && text && text[text.length - 1] !== '\n') {
|
||||||
|
text += '\n'
|
||||||
|
}
|
||||||
|
// 递归获取子节点的文本
|
||||||
|
if (node.children) {
|
||||||
|
traversal(node.children)
|
||||||
|
}
|
||||||
|
if (isBlock && text[text.length - 1] !== '\n') {
|
||||||
|
text += '\n'
|
||||||
|
} else if (node.name === 'td' || node.name === 'th') {
|
||||||
|
text += '\t'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(nodes || this.nodes)
|
||||||
|
return text
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取内容大小和位置
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
getRect () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.createSelectorQuery()
|
||||||
|
// #ifndef MP-ALIPAY
|
||||||
|
.in(this)
|
||||||
|
// #endif
|
||||||
|
.select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 暂停播放媒体
|
||||||
|
*/
|
||||||
|
pauseMedia () {
|
||||||
|
for (let i = (this._videos || []).length; i--;) {
|
||||||
|
this._videos[i].pause()
|
||||||
|
}
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
let page = this.$parent
|
||||||
|
while (!page.$scope) page = page.$parent
|
||||||
|
page.$scope.$getAppWebview().evalJS(command)
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
this.$refs.web.evalJs(command)
|
||||||
|
// #endif
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 设置内容
|
||||||
|
* @param {String} content html 内容
|
||||||
|
* @param {Boolean} append 是否在尾部追加
|
||||||
|
*/
|
||||||
|
setContent (content, append) {
|
||||||
|
if (!append || !this.imgList) {
|
||||||
|
this.imgList = []
|
||||||
|
}
|
||||||
|
const nodes = new Parser(this).parse(content)
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
if (this._ready) {
|
||||||
|
this._set(nodes, append)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
|
||||||
|
|
||||||
|
// #ifndef APP-PLUS-NVUE
|
||||||
|
this._videos = []
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this._hook('onLoad')
|
||||||
|
this.$emit('load')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 等待图片加载完毕
|
||||||
|
let height
|
||||||
|
clearInterval(this._timer)
|
||||||
|
this._timer = setInterval(() => {
|
||||||
|
this.getRect().then(rect => {
|
||||||
|
// 350ms 总高度无变化就触发 ready 事件
|
||||||
|
if (rect.height === height) {
|
||||||
|
this.$emit('ready', rect)
|
||||||
|
clearInterval(this._timer)
|
||||||
|
}
|
||||||
|
height = rect.height
|
||||||
|
}).catch(() => { })
|
||||||
|
}, 350)
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 调用插件钩子函数
|
||||||
|
*/
|
||||||
|
_hook (name) {
|
||||||
|
for (let i = plugins.length; i--;) {
|
||||||
|
if (this.plugins[i][name]) {
|
||||||
|
this.plugins[i][name]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS-NVUE
|
||||||
|
/**
|
||||||
|
* @description 设置内容
|
||||||
|
*/
|
||||||
|
_set (nodes, append) {
|
||||||
|
this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes) + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 接收到 web-view 消息
|
||||||
|
*/
|
||||||
|
_onMessage (e) {
|
||||||
|
const message = e.detail.data[0]
|
||||||
|
switch (message.action) {
|
||||||
|
// web-view 初始化完毕
|
||||||
|
case 'onJSBridgeReady':
|
||||||
|
this._ready = true
|
||||||
|
if (this.nodes) {
|
||||||
|
this._set(this.nodes)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// 内容 dom 加载完毕
|
||||||
|
case 'onLoad':
|
||||||
|
this.height = message.height
|
||||||
|
this._hook('onLoad')
|
||||||
|
this.$emit('load')
|
||||||
|
break
|
||||||
|
// 所有图片加载完毕
|
||||||
|
case 'onReady':
|
||||||
|
this.getRect().then(res => {
|
||||||
|
this.$emit('ready', res)
|
||||||
|
}).catch(() => { })
|
||||||
|
break
|
||||||
|
// 总高度发生变化
|
||||||
|
case 'onHeightChange':
|
||||||
|
this.height = message.height
|
||||||
|
break
|
||||||
|
// 图片点击
|
||||||
|
case 'onImgTap':
|
||||||
|
this.$emit('imgtap', message.attrs)
|
||||||
|
if (this.previewImg) {
|
||||||
|
uni.previewImage({
|
||||||
|
current: parseInt(message.attrs.i),
|
||||||
|
urls: this.imgList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// 链接点击
|
||||||
|
case 'onLinkTap': {
|
||||||
|
const href = message.attrs.href
|
||||||
|
this.$emit('linktap', message.attrs)
|
||||||
|
if (href) {
|
||||||
|
// 锚点跳转
|
||||||
|
if (href[0] === '#') {
|
||||||
|
if (this.useAnchor) {
|
||||||
|
dom.scrollToElement(this.$refs.web, {
|
||||||
|
offset: message.offset
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if (href.includes('://')) {
|
||||||
|
// 打开外链
|
||||||
|
if (this.copyLink) {
|
||||||
|
plus.runtime.openWeb(href)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: href,
|
||||||
|
fail () {
|
||||||
|
uni.switchTab({
|
||||||
|
url: href
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'onPlay':
|
||||||
|
this.$emit('play')
|
||||||
|
break
|
||||||
|
// 获取到锚点的偏移量
|
||||||
|
case 'getOffset':
|
||||||
|
if (typeof message.offset === 'number') {
|
||||||
|
dom.scrollToElement(this.$refs.web, {
|
||||||
|
offset: message.offset + this._navigateTo.offset
|
||||||
|
})
|
||||||
|
this._navigateTo.resolve()
|
||||||
|
} else {
|
||||||
|
this._navigateTo.reject(Error('Label not found'))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// 点击
|
||||||
|
case 'onClick':
|
||||||
|
this.$emit('tap')
|
||||||
|
this.$emit('click')
|
||||||
|
break
|
||||||
|
// 出错
|
||||||
|
case 'onError':
|
||||||
|
this.$emit('error', {
|
||||||
|
source: message.source,
|
||||||
|
attrs: message.attrs
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* #ifndef APP-PLUS-NVUE */
|
||||||
|
/* 根节点样式 */
|
||||||
|
._root {
|
||||||
|
padding: 1px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 长按复制 */
|
||||||
|
._select {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
/* 提示条 */
|
||||||
|
._tooltip_contain {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
left: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tooltip {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
padding: 0 3px;
|
||||||
|
overflow: scroll;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 30px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tooltip_item {
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
padding: 0 2vw;
|
||||||
|
line-height: 30px;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图片宽度滚动条 */
|
||||||
|
._slider {
|
||||||
|
position: absolute;
|
||||||
|
left: 20px;
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tooltip,
|
||||||
|
._slider {
|
||||||
|
background-color: black;
|
||||||
|
border-radius: 3px;
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,972 @@
|
||||||
|
<template>
|
||||||
|
<view @tap="nodeTap" :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="(ctrl.root?'border:1px solid black;padding:5px;display:block;':'')+attrs.style">
|
||||||
|
<block v-for="(n, i) in childs" v-bind:key="i">
|
||||||
|
<!-- 图片 -->
|
||||||
|
<!-- 占位图 -->
|
||||||
|
<image v-if="n.name==='img'&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
|
||||||
|
<!-- 显示图片 -->
|
||||||
|
<!-- #ifdef H5 || (APP-PLUS && VUE2) -->
|
||||||
|
<img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl['e'+i]?'border:1px dashed black;padding:3px;':'')+(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 || APP-PLUS -->
|
||||||
|
<image v-if="n.name==='img'" :id="n.attrs.id||('n'+i)" :class="'_img '+n.attrs.class" :style="(ctrl['e'+i]?'border:1px dashed black;padding:3px;':'')+(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:'+(ctrl['h'+i]||1)+'px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="!opts[5]&&opts[3]&&!n.attrs.ignore" :image-menu-prevent="opts[5]||!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-PLUS && VUE3 -->
|
||||||
|
<image v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl['e'+i]?'border:1px dashed black;padding:3px;':'')+(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- 文本 -->
|
||||||
|
<text v-else-if="n.type==='text'&&!ctrl['e'+i]" :data-i="i" :user-select="opts[4]" :decode="!opts[5]" @tap="editStart">{{n.text}}
|
||||||
|
<text v-if="!n.text" style="color:gray">{{opts[6]||'请输入'}}</text>
|
||||||
|
</text>
|
||||||
|
<text v-else-if="n.type==='text'&&ctrl['e'+i]===1" :data-i="i" style="border:1px dashed black;min-width:50px;width:auto;padding:5px;display:block" @tap.stop="editStart">{{n.text}}
|
||||||
|
<text v-if="!n.text" style="color:gray">{{opts[6]||'请输入'}}</text>
|
||||||
|
</text>
|
||||||
|
<textarea v-else-if="n.type==='text'" style="border:1px dashed black;min-width:50px;width:auto;padding:5px" auto-height maxlength="-1" :focus="ctrl['e'+i]===3" :value="n.text" :data-i="i" @input="editInput" @blur="editEnd" />
|
||||||
|
<text v-else-if="n.name==='br'">\n</text>
|
||||||
|
<!-- 链接 -->
|
||||||
|
<view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
|
||||||
|
<node name="span" :childs="n.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children']" style="display:inherit" />
|
||||||
|
</view>
|
||||||
|
<!-- 视频 -->
|
||||||
|
<!-- #ifdef APP-PLUS -->
|
||||||
|
<view v-else-if="n.html" :data-i="i" @tap="mediaTap" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef APP-PLUS -->
|
||||||
|
<video :show-center-play-btn="!opts[5]" @tap="mediaTap" v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef H5 || APP-PLUS -->
|
||||||
|
<iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
|
||||||
|
<embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
|
||||||
|
<!-- 音频 -->
|
||||||
|
<audio @tap="mediaTap" v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<view v-else-if="(n.name==='table'&&(n.c||opts[5]))||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
|
||||||
|
<node v-if="n.name==='li'" :childs="n.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children']" />
|
||||||
|
<view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
|
||||||
|
<node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children.'+x+'.children']" />
|
||||||
|
<block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
|
||||||
|
<view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
|
||||||
|
<node :childs="tr.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children.'+x+'.children.'+y+'.children']" />
|
||||||
|
</view>
|
||||||
|
<view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
|
||||||
|
<view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
|
||||||
|
<node :childs="td.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children.'+x+'.children.'+y+'.children.'+z+'.children']" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 富文本 -->
|
||||||
|
<!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||||
|
<rich-text v-else-if="!opts[5]&&!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
|
||||||
|
<rich-text v-else-if="!opts[5]&&!n.c" :id="n.attrs.id" :style="n.f+';display:inline'" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- 继续递归 -->
|
||||||
|
<view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
|
||||||
|
<node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children.'+j+'.children']" />
|
||||||
|
</view>
|
||||||
|
<node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="[opts[0],opts[1],opts[2],opts[3],opts[4],opts[5],opts[6],opts[7]+'.'+i+'.children']" />
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script module="handler" lang="wxs">
|
||||||
|
// 行内标签列表
|
||||||
|
var inlineTags = {
|
||||||
|
abbr: true,
|
||||||
|
b: true,
|
||||||
|
big: true,
|
||||||
|
code: true,
|
||||||
|
del: true,
|
||||||
|
em: true,
|
||||||
|
i: true,
|
||||||
|
ins: true,
|
||||||
|
label: true,
|
||||||
|
q: true,
|
||||||
|
small: true,
|
||||||
|
span: true,
|
||||||
|
strong: true,
|
||||||
|
sub: true,
|
||||||
|
sup: true
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description 判断是否为行内标签
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
isInline: function (tagName, style) {
|
||||||
|
return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
function getTop(e) {
|
||||||
|
let top
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
top = e.touches[0].pageY
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
top = e.detail.pageY
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5 || MP-ALIPAY || APP-PLUS
|
||||||
|
top = e.detail.y
|
||||||
|
// #endif
|
||||||
|
if (top - e.currentTarget.offsetTop < 150)
|
||||||
|
top = e.currentTarget.offsetTop
|
||||||
|
if (top < 30)
|
||||||
|
top += 70
|
||||||
|
return top - 30
|
||||||
|
}
|
||||||
|
|
||||||
|
import node from './node'
|
||||||
|
export default {
|
||||||
|
name: 'node',
|
||||||
|
options: {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
virtualHost: true,
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
addGlobalClass: false
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
ctrl: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
attrs: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
childs: Array,
|
||||||
|
opts: Array
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
|
||||||
|
// #ifndef H5 && VUE3
|
||||||
|
node
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
|
||||||
|
})
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
if (this.opts[0]) {
|
||||||
|
let i
|
||||||
|
for (i = this.childs.length; i--;) {
|
||||||
|
if (this.childs[i].name === 'img') break
|
||||||
|
}
|
||||||
|
if (i !== -1) {
|
||||||
|
this.observer = uni.createIntersectionObserver(this).relativeToViewport({
|
||||||
|
top: 500,
|
||||||
|
bottom: 500
|
||||||
|
})
|
||||||
|
this.observer.observe('._img', res => {
|
||||||
|
if (res.intersectionRatio) {
|
||||||
|
this.$set(this.ctrl, 'load', 1)
|
||||||
|
this.observer.disconnect()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
if (this.root._edit === this) {
|
||||||
|
this.root._edit = undefined
|
||||||
|
}
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
if (this.observer) {
|
||||||
|
this.observer.disconnect()
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
methods:{editStart (e) {
|
||||||
|
if (this.opts[5]) {
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
if (!this.ctrl['e' + i]) {
|
||||||
|
// 显示虚线框
|
||||||
|
this.$set(this.ctrl, 'e' + i, 1)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.root._mask.push(() => this.$set(this.ctrl, 'e' + i, 0))
|
||||||
|
}, 50)
|
||||||
|
this.root._edit = this
|
||||||
|
this.i = i
|
||||||
|
this.cursor = this.childs[i].text.length
|
||||||
|
} else {
|
||||||
|
this.root._mask.pop()
|
||||||
|
this.root._maskTap()
|
||||||
|
// 将 text 转为 textarea
|
||||||
|
this.$set(this.ctrl, 'e' + i, 2)
|
||||||
|
// 延时对焦,避免高度错误
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$set(this.ctrl, 'e' + i, 3)
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},editInput (e) {
|
||||||
|
const i = e.target.dataset.i
|
||||||
|
// 替换连续空格
|
||||||
|
const value = e.detail.value.replace(/ {2,}/, $ => {
|
||||||
|
let res = '\xa0'
|
||||||
|
for (let i = 1; i < $.length; i++) {
|
||||||
|
res += '\xa0'
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
this.root._editVal(`${this.opts[7]}.${i}.text`, this.childs[i].text, value) // 记录编辑历史
|
||||||
|
this.cursor = e.detail.cursor
|
||||||
|
},editEnd (e) {
|
||||||
|
const i = e.target.dataset.i
|
||||||
|
this.$set(this.ctrl, 'e' + i, 0)
|
||||||
|
// 更新到视图
|
||||||
|
this.root._setData(`${this.opts[7]}.${i}.text`, e.detail.value.replace(/ {2}/g, '\xa0 '))
|
||||||
|
if (e.detail.cursor !== undefined) {
|
||||||
|
this.cursor = e.detail.cursor
|
||||||
|
}
|
||||||
|
},insert (node) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const childs = this.childs.slice(0)
|
||||||
|
if (!childs[this.i]) {
|
||||||
|
childs.push(node)
|
||||||
|
} else if (childs[this.i].text) {
|
||||||
|
// 在文本中插入
|
||||||
|
const text = childs[this.i].text
|
||||||
|
const list = []
|
||||||
|
if (this.cursor) {
|
||||||
|
list.push({
|
||||||
|
type: 'text',
|
||||||
|
text: text.substring(0, this.cursor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
list.push(node)
|
||||||
|
if (this.cursor < text.length) {
|
||||||
|
list.push({
|
||||||
|
type: 'text',
|
||||||
|
text: text.substring(this.cursor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
childs.splice(this.i, 1, ...list)
|
||||||
|
} else {
|
||||||
|
childs.splice(parseInt(this.i) + 1, 0, node)
|
||||||
|
}
|
||||||
|
this.root._editVal(this.opts[7], this.childs, childs, true)
|
||||||
|
this.i = parseInt(this.i) + 1
|
||||||
|
}, 200)
|
||||||
|
},remove (i) {
|
||||||
|
const arr = this.childs.slice(0)
|
||||||
|
const delEle = arr.splice(i, 1)[0]
|
||||||
|
if (delEle.name === 'img' || delEle.name === 'video' || delEle.name === 'audio') {
|
||||||
|
let src = delEle.attrs.src
|
||||||
|
if (delEle.src) {
|
||||||
|
src = delEle.src.length === 1 ? delEle.src[0] : delEle.src
|
||||||
|
}
|
||||||
|
this.root.$emit('remove', {
|
||||||
|
type: delEle.name,
|
||||||
|
src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.root._edit = undefined
|
||||||
|
this.root._maskTap()
|
||||||
|
this.root._editVal(this.opts[7], this.childs, arr, true)
|
||||||
|
},nodeTap (e) {
|
||||||
|
if (this.opts[5]) {
|
||||||
|
if (this.root._lock) return
|
||||||
|
this.root._lock = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.root._lock = false
|
||||||
|
}, 50)
|
||||||
|
if (this.ctrl['e' + this.i] === 3) return
|
||||||
|
this.root._maskTap()
|
||||||
|
this.root._edit = this
|
||||||
|
let start = this.opts[7].lastIndexOf('children.')
|
||||||
|
if (start !== -1) {
|
||||||
|
start += 9
|
||||||
|
} else {
|
||||||
|
start = 6
|
||||||
|
}
|
||||||
|
const i = parseInt(this.opts[7].substring(start, this.opts[7].lastIndexOf('.children')))
|
||||||
|
let parent = this.$parent
|
||||||
|
while (parent && parent.$options.name !== 'node') {
|
||||||
|
parent = parent.$parent
|
||||||
|
}
|
||||||
|
if (!parent || this.opts[7].length - parent.opts[7].length > 15) return
|
||||||
|
// 显示实线框
|
||||||
|
this.$set(this.ctrl, 'root', 1)
|
||||||
|
this.root._mask.push(() => this.$set(this.ctrl, 'root', 0))
|
||||||
|
if (this.childs.length === 1 && this.childs[0].type === 'text' && !this.ctrl.e0) {
|
||||||
|
this.$set(this.ctrl, 'e0', 1)
|
||||||
|
this.root._mask.push(() => this.$set(this.ctrl, 'e0', 0))
|
||||||
|
this.i = 0
|
||||||
|
this.cursor = this.childs[0].text.length
|
||||||
|
}
|
||||||
|
const items = this.root._getItem(parent.childs[i], i !== 0, i !== parent.childs.length - 1)
|
||||||
|
this.root._tooltip({
|
||||||
|
top: getTop(e),
|
||||||
|
items,
|
||||||
|
success: tapIndex => {
|
||||||
|
if (items[tapIndex] === '大小') {
|
||||||
|
// 改变字体大小
|
||||||
|
const style = parent.childs[i].attrs.style || ''
|
||||||
|
let value = style.match(/;font-size:([0-9]+)px/)
|
||||||
|
if (value) {
|
||||||
|
value = parseInt(value[1])
|
||||||
|
} else {
|
||||||
|
value = 16
|
||||||
|
}
|
||||||
|
this.root._slider({
|
||||||
|
min: 10,
|
||||||
|
max: 30,
|
||||||
|
value,
|
||||||
|
top: getTop(e),
|
||||||
|
changing: val => {
|
||||||
|
if (Math.abs(val - value) > 2) {
|
||||||
|
// 字号变换超过 2 时更新到视图
|
||||||
|
parent.changeStyle('font-size', i, val + 'px', value + 'px')
|
||||||
|
value = e.detail.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
change: val => {
|
||||||
|
if (val !== value) {
|
||||||
|
parent.changeStyle('font-size', i, val + 'px', value + 'px')
|
||||||
|
}
|
||||||
|
this.root._editVal(`${parent.opts[7]}.${i}.attrs.style`, style, parent.childs[i].attrs.style)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (items[tapIndex] === '上移' || items[tapIndex] === '下移') {
|
||||||
|
const arr = parent.childs.slice(0)
|
||||||
|
const item = arr[i]
|
||||||
|
if (items[tapIndex] === '上移') {
|
||||||
|
arr[i] = arr[i - 1]
|
||||||
|
arr[i - 1] = item
|
||||||
|
} else {
|
||||||
|
arr[i] = arr[i + 1]
|
||||||
|
arr[i + 1] = item
|
||||||
|
}
|
||||||
|
this.root._editVal(parent.opts[7], parent.childs, arr, true)
|
||||||
|
} else if (items[tapIndex] === '删除') {
|
||||||
|
parent.remove(i)
|
||||||
|
} else {
|
||||||
|
const style = parent.childs[i].attrs.style || ''
|
||||||
|
let newStyle = ''
|
||||||
|
const item = items[tapIndex]
|
||||||
|
let name
|
||||||
|
let value
|
||||||
|
if (item === '斜体') {
|
||||||
|
name = 'font-style'
|
||||||
|
value = 'italic'
|
||||||
|
} else if (item === '粗体') {
|
||||||
|
name = 'font-weight'
|
||||||
|
value = 'bold'
|
||||||
|
} else if (item === '下划线') {
|
||||||
|
name = 'text-decoration'
|
||||||
|
value = 'underline'
|
||||||
|
} else if (item === '居中') {
|
||||||
|
name = 'text-align'
|
||||||
|
value = 'center'
|
||||||
|
} else if (item === '缩进') {
|
||||||
|
name = 'text-indent'
|
||||||
|
value = '2em'
|
||||||
|
}
|
||||||
|
if (style.includes(name + ':')) {
|
||||||
|
// 已有则取消
|
||||||
|
newStyle = style.replace(new RegExp(name + ':[^;]+'), '')
|
||||||
|
} else {
|
||||||
|
// 没有则添加
|
||||||
|
newStyle = style + ';' + name + ':' + value
|
||||||
|
}
|
||||||
|
this.root._editVal(`${parent.opts[7]}.${i}.attrs.style`, style, newStyle, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},mediaTap (e) {
|
||||||
|
if (this.opts[5]) {
|
||||||
|
const i = e.target.dataset.i
|
||||||
|
const node = this.childs[i]
|
||||||
|
const items = this.root._getItem(node)
|
||||||
|
this.root._edit = this
|
||||||
|
this.i = i
|
||||||
|
this.root._tooltip({
|
||||||
|
top: e.target.offsetTop - 30,
|
||||||
|
items,
|
||||||
|
success: tapIndex => {
|
||||||
|
switch (items[tapIndex]) {
|
||||||
|
case '封面':
|
||||||
|
// 设置封面
|
||||||
|
this.root.getSrc('img', node.attrs.poster || '').then(url => {
|
||||||
|
this.root._editVal(`${this.opts[7]}.${i}.attrs.poster`, node.attrs.poster, url instanceof Array ? url[0] : url, true)
|
||||||
|
}).catch(() => { })
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.remove(i)
|
||||||
|
break
|
||||||
|
case '循环':
|
||||||
|
case '不循环':
|
||||||
|
// 切换循环播放
|
||||||
|
this.root._setData(`${this.opts[7]}.${i}.attrs.loop`, !node.attrs.loop)
|
||||||
|
uni.showToast({
|
||||||
|
title: '成功'
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case '自动播放':
|
||||||
|
case '不自动播放':
|
||||||
|
// 切换自动播放播放
|
||||||
|
this.root._setData(`${this.opts[7]}.${i}.attrs.autoplay`, !node.attrs.autoplay)
|
||||||
|
uni.showToast({
|
||||||
|
title: '成功'
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 避免上层出现点击态
|
||||||
|
this.root._lock = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.root._lock = false
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
},changeStyle (name, i, value, oldVal) {
|
||||||
|
let style = this.childs[i].attrs.style || ''
|
||||||
|
if (style.includes(';' + name + ':' + oldVal)) {
|
||||||
|
// style 中已经有
|
||||||
|
style = style.replace(';' + name + ':' + oldVal, ';' + name + ':' + value)
|
||||||
|
} else {
|
||||||
|
// 没有则新增
|
||||||
|
style += ';' + name + ':' + value
|
||||||
|
}
|
||||||
|
this.root._setData(`${this.opts[7]}.${i}.attrs.style`, style)
|
||||||
|
},
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
toJSON () { },
|
||||||
|
// #endif
|
||||||
|
/**
|
||||||
|
* @description 播放视频事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
play (e) {
|
||||||
|
this.root.$emit('play')
|
||||||
|
// #ifndef APP-PLUS
|
||||||
|
if (this.root.pauseVideo) {
|
||||||
|
let flag = false
|
||||||
|
const id = e.target.id
|
||||||
|
for (let i = this.root._videos.length; i--;) {
|
||||||
|
if (this.root._videos[i].id === id) {
|
||||||
|
flag = true
|
||||||
|
} else {
|
||||||
|
this.root._videos[i].pause() // 自动暂停其他视频
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将自己加入列表
|
||||||
|
if (!flag) {
|
||||||
|
const ctx = uni.createVideoContext(id
|
||||||
|
// #ifndef MP-BAIDU
|
||||||
|
, this
|
||||||
|
// #endif
|
||||||
|
)
|
||||||
|
ctx.id = id
|
||||||
|
this.root._videos.push(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 图片点击事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
imgTap (e) {
|
||||||
|
if (!this.opts[5]) {
|
||||||
|
const node = this.childs[e.currentTarget.dataset.i]
|
||||||
|
if (node.a) {
|
||||||
|
this.linkTap(node.a)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (node.attrs.ignore) return
|
||||||
|
// #ifdef H5 || APP-PLUS
|
||||||
|
node.attrs.src = node.attrs.src || node.attrs['data-src']
|
||||||
|
// #endif
|
||||||
|
this.root.$emit('imgtap', node.attrs)
|
||||||
|
// 自动预览图片
|
||||||
|
if (this.root.previewImg) {
|
||||||
|
uni.previewImage({
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
showmenu: this.root.showImgMenu,
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
enablesavephoto: this.root.showImgMenu,
|
||||||
|
enableShowPhotoDownload: this.root.showImgMenu,
|
||||||
|
// #endif
|
||||||
|
current: parseInt(node.attrs.i),
|
||||||
|
urls: this.root.imgList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
const node = this.childs[i]
|
||||||
|
const items = this.root._getItem(node)
|
||||||
|
this.root._edit = this
|
||||||
|
this.i = i
|
||||||
|
this.root._maskTap()
|
||||||
|
this.$set(this.ctrl, 'e' + i, 1)
|
||||||
|
this.root._mask.push(() => this.$set(this.ctrl, 'e' + i, 0))
|
||||||
|
this.root._tooltip({
|
||||||
|
top: getTop(e),
|
||||||
|
items,
|
||||||
|
success: tapIndex => {
|
||||||
|
if (items[tapIndex] === '换图') {
|
||||||
|
// 换图
|
||||||
|
this.root.getSrc('img', node.attrs.src || '').then(url => {
|
||||||
|
this.root._editVal(this.opts[7] + '.' + i + '.attrs.src', node.attrs.src, url instanceof Array ? url[0] : url, true)
|
||||||
|
}).catch(() => { })
|
||||||
|
} else if (items[tapIndex] === '宽度') {
|
||||||
|
// 更改宽度
|
||||||
|
const style = node.attrs.style || ''
|
||||||
|
let value = style.match(/max-width:([0-9]+)%/)
|
||||||
|
if (value) {
|
||||||
|
value = parseInt(value[1])
|
||||||
|
} else {
|
||||||
|
value = 100
|
||||||
|
}
|
||||||
|
this.root._slider({
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
value,
|
||||||
|
top: getTop(e),
|
||||||
|
changing: val => {
|
||||||
|
// 变化超过 5% 更新时视图
|
||||||
|
if (Math.abs(val - value) > 5) {
|
||||||
|
this.changeStyle('max-width', i, val + '%', value + '%')
|
||||||
|
value = val
|
||||||
|
}
|
||||||
|
},
|
||||||
|
change: val => {
|
||||||
|
if (val !== value) {
|
||||||
|
this.changeStyle('max-width', i, val + '%', value + '%')
|
||||||
|
value = val
|
||||||
|
}
|
||||||
|
this.root._editVal(this.opts[7] + '.' + i + '.attrs.style', style, this.childs[i].attrs.style)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (items[tapIndex] === '超链接') {
|
||||||
|
// 将图片设置为链接
|
||||||
|
this.root.getSrc('link', node.a ? node.a.href : '').then(url => {
|
||||||
|
// 如果有 a 标签则替换 href
|
||||||
|
if (node.a) {
|
||||||
|
this.root._editVal(this.opts[7] + '.' + i + '.a.href', node.a.href, url, true)
|
||||||
|
} else {
|
||||||
|
const link = {
|
||||||
|
name: 'a',
|
||||||
|
attrs: {
|
||||||
|
href: url
|
||||||
|
},
|
||||||
|
children: [node]
|
||||||
|
}
|
||||||
|
node.a = link.attrs
|
||||||
|
this.root._editVal(this.opts[7] + '.' + i, node, link, true)
|
||||||
|
}
|
||||||
|
wx.showToast({
|
||||||
|
title: '成功'
|
||||||
|
})
|
||||||
|
}).catch(() => { })
|
||||||
|
} else if (items[tapIndex] === '预览图') {
|
||||||
|
// 设置预览图链接
|
||||||
|
this.root.getSrc('img', node.attrs['original-src'] || '').then(url => {
|
||||||
|
this.root._editVal(this.opts[7] + '.' + i + '.attrs.original-src', node.attrs['original-src'], url instanceof Array ? url[0] : url, true)
|
||||||
|
uni.showToast({
|
||||||
|
title: '成功'
|
||||||
|
})
|
||||||
|
}).catch(() => { })
|
||||||
|
} else if (items[tapIndex] === '删除') {
|
||||||
|
this.remove(i)
|
||||||
|
} else {
|
||||||
|
// 禁用 / 启用预览
|
||||||
|
this.root._setData(this.opts[7] + '.' + i + '.attrs.ignore', !node.attrs.ignore)
|
||||||
|
uni.showToast({
|
||||||
|
title: '成功'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.root._lock = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.root._lock = false
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @description 图片长按
|
||||||
|
*/
|
||||||
|
imgLongTap (e) {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
const attrs = this.childs[e.currentTarget.dataset.i].attrs
|
||||||
|
if (this.opts[3] && !attrs.ignore) {
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ['保存图片'],
|
||||||
|
success: () => {
|
||||||
|
const save = path => {
|
||||||
|
uni.saveImageToPhotosAlbum({
|
||||||
|
filePath: path,
|
||||||
|
success () {
|
||||||
|
uni.showToast({
|
||||||
|
title: '保存成功'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.root.imgList[attrs.i].startsWith('http')) {
|
||||||
|
uni.downloadFile({
|
||||||
|
url: this.root.imgList[attrs.i],
|
||||||
|
success: res => save(res.tempFilePath)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
save(this.root.imgList[attrs.i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 图片加载完成事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
imgLoad(e) {
|
||||||
|
// #ifdef MP-WEIXIN || MP-QQ
|
||||||
|
if (this.opts[5])
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const id = this.childs[i].attrs.id || ('n' + i)
|
||||||
|
uni.createSelectorQuery().in(this).select('#' + id).boundingClientRect().exec(res => {
|
||||||
|
this.$set(this.ctrl, 'h'+i, res[0].height)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
/* #ifndef H5 || (APP-PLUS && VUE2) */
|
||||||
|
if (!this.childs[i].w) {
|
||||||
|
this.$set(this.ctrl, i, e.detail.width)
|
||||||
|
if (this.opts[5]) {
|
||||||
|
const path = this.opts[7] + '.' + i + '.attrs.'
|
||||||
|
if (e.detail.width < 150)
|
||||||
|
this.root._setData(path + 'ignore', 'T')
|
||||||
|
this.root._setData(path + 'width', e.detail.width.toString())
|
||||||
|
}
|
||||||
|
} else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
|
||||||
|
// 加载完毕,取消加载中占位图
|
||||||
|
this.$set(this.ctrl, i, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 链接点击事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
linkTap (e) {
|
||||||
|
if (!this.opts[5]) {
|
||||||
|
const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
|
||||||
|
const attrs = node.attrs || e
|
||||||
|
const href = attrs.href
|
||||||
|
this.root.$emit('linktap', Object.assign({
|
||||||
|
innerText: this.root.getText(node.children || []) // 链接内的文本内容
|
||||||
|
}, attrs))
|
||||||
|
if (href) {
|
||||||
|
if (href[0] === '#') {
|
||||||
|
// 跳转锚点
|
||||||
|
this.root.navigateTo(href.substring(1)).catch(() => { })
|
||||||
|
} else if (href.split('?')[0].includes('://')) {
|
||||||
|
// 复制外部链接
|
||||||
|
if (this.root.copyLink) {
|
||||||
|
// #ifdef H5
|
||||||
|
window.open(href)
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: href,
|
||||||
|
success: () =>
|
||||||
|
uni.showToast({
|
||||||
|
title: '链接已复制'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
plus.runtime.openWeb(href)
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 跳转页面
|
||||||
|
uni.navigateTo({
|
||||||
|
url: href,
|
||||||
|
fail () {
|
||||||
|
uni.switchTab({
|
||||||
|
url: href,
|
||||||
|
fail () { }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
const node = this.childs[i]
|
||||||
|
const items = this.root._getItem(node)
|
||||||
|
this.root._tooltip({
|
||||||
|
top: getTop(e),
|
||||||
|
items,
|
||||||
|
success: tapIndex => {
|
||||||
|
if (items[tapIndex] === '更换链接') {
|
||||||
|
this.root.getSrc('link', node.attrs.href).then(url => {
|
||||||
|
this.root._editVal(this.opts[7] + '.' + i + '.attrs.href', node.attrs.href, url, true)
|
||||||
|
uni.showToast({
|
||||||
|
title: '成功'
|
||||||
|
})
|
||||||
|
}).catch(() => { })
|
||||||
|
} else {
|
||||||
|
this.remove(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @description 错误事件
|
||||||
|
* @param {Event} e
|
||||||
|
*/
|
||||||
|
mediaError (e) {
|
||||||
|
const i = e.currentTarget.dataset.i
|
||||||
|
const node = this.childs[i]
|
||||||
|
// 加载其他源
|
||||||
|
if (node.name === 'video' || node.name === 'audio') {
|
||||||
|
let index = (this.ctrl[i] || 0) + 1
|
||||||
|
if (index > node.src.length) {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
if (index < node.src.length) {
|
||||||
|
this.$set(this.ctrl, i, index)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if (node.name === 'img') {
|
||||||
|
// #ifdef H5 && VUE3
|
||||||
|
if (this.opts[0] && !this.ctrl.load) return
|
||||||
|
// #endif
|
||||||
|
// 显示错误占位图
|
||||||
|
if (this.opts[2]) {
|
||||||
|
this.$set(this.ctrl, i, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.root) {
|
||||||
|
this.root.$emit('error', {
|
||||||
|
source: node.name,
|
||||||
|
attrs: node.attrs,
|
||||||
|
// #ifndef H5 && VUE3
|
||||||
|
errMsg: e.detail.errMsg
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>/* #ifndef H5 || MP-ALIPAY || APP-PLUS */
|
||||||
|
/deep/ ._address,
|
||||||
|
/deep/ ._article,
|
||||||
|
/deep/ ._aside,
|
||||||
|
/deep/ ._body,
|
||||||
|
/deep/ ._caption,
|
||||||
|
/deep/ ._center,
|
||||||
|
/deep/ ._cite,
|
||||||
|
/deep/ ._footer,
|
||||||
|
/deep/ ._header,
|
||||||
|
/deep/ ._html,
|
||||||
|
/deep/ ._nav,
|
||||||
|
/deep/ ._pre,
|
||||||
|
/deep/ ._section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
/deep/ ._video {
|
||||||
|
width: 300px;
|
||||||
|
height: 225px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
/* a 标签默认效果 */
|
||||||
|
._a {
|
||||||
|
padding: 1.5px 0 1.5px 0;
|
||||||
|
color: #366092;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a 标签点击态效果 */
|
||||||
|
._hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图片默认效果 */
|
||||||
|
._img {
|
||||||
|
max-width: 100%;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内部样式 */
|
||||||
|
|
||||||
|
._block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
._b,
|
||||||
|
._strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
._code {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
._del {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
._em,
|
||||||
|
._i {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h2 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h3 {
|
||||||
|
font-size: 1.17em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h5 {
|
||||||
|
font-size: 0.83em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h6 {
|
||||||
|
font-size: 0.67em;
|
||||||
|
}
|
||||||
|
|
||||||
|
._h1,
|
||||||
|
._h2,
|
||||||
|
._h3,
|
||||||
|
._h4,
|
||||||
|
._h5,
|
||||||
|
._h6 {
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
._image {
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ins {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
._li {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ol,
|
||||||
|
._ul {
|
||||||
|
display: block;
|
||||||
|
padding-left: 40px;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
._q::before {
|
||||||
|
content: '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
._q::after {
|
||||||
|
content: '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
._sub {
|
||||||
|
font-size: smaller;
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
._sup {
|
||||||
|
font-size: smaller;
|
||||||
|
vertical-align: super;
|
||||||
|
}
|
||||||
|
|
||||||
|
._thead,
|
||||||
|
._tbody,
|
||||||
|
._tfoot {
|
||||||
|
display: table-row-group;
|
||||||
|
}
|
||||||
|
|
||||||
|
._tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
._td,
|
||||||
|
._th {
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
._th {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ul ._ul {
|
||||||
|
margin: 0;
|
||||||
|
list-style-type: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
._ul ._ul ._ul {
|
||||||
|
list-style-type: square;
|
||||||
|
}
|
||||||
|
|
||||||
|
._abbr,
|
||||||
|
._b,
|
||||||
|
._code,
|
||||||
|
._del,
|
||||||
|
._em,
|
||||||
|
._i,
|
||||||
|
._ins,
|
||||||
|
._label,
|
||||||
|
._q,
|
||||||
|
._span,
|
||||||
|
._strong,
|
||||||
|
._sub,
|
||||||
|
._sup {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifdef APP-PLUS */
|
||||||
|
._video {
|
||||||
|
width: 300px;
|
||||||
|
height: 225px;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
<template>
|
||||||
|
<view class="rider-swipeout-wrap" :style="{ backgroundColor: backgroundColor }">
|
||||||
|
<view class="rider-swipeout-item" :class="[isShowBtn ? 'swipe-action-show' : '']" :style="{ transform: 'translate(' + position.pageX + 'px,0)' }">
|
||||||
|
<view class="rider-swipeout-content" @touchstart="handlerTouchstart" @touchmove="handlerTouchmove" @touchend="handlerTouchend" @mousedown="handlerTouchstart" @mousemove="handlerTouchmove" @mouseup="handlerTouchend">
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</view>
|
||||||
|
<view class="rider-swipeout-button-right-group" v-if="actions.length > 0" @touchend.stop="loop">
|
||||||
|
<view class="rider-swipeout-button-right-item" v-for="(item, index) in actions" :key="index" :style="{ backgroundColor: item.background || '#f7f7f7', color: item.color, width: item.width + 'px', height: item.width + 'px', }" :data-index="index" @tap="handlerButton">
|
||||||
|
<!-- <image :src="item.icon" v-if="item.icon" :style="{ width: px(item.imgWidth), height: px(item.imgHeight) }"></image> -->
|
||||||
|
<u-icon v-if="item.icon" :name="item.icon" :size="item.fontsize"></u-icon>
|
||||||
|
<text v-else :style="{ fontSize: `${item.fontsize}rpx`}">{{ item.name }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!--actions长度设置为0,可直接传按钮进来-->
|
||||||
|
<view class="rider-swipeout-button-right-group" @touchend.stop="loop" @tap="handlerParentButton" v-if="actions.length === 0" :style="{ width: operateWidth + 'px', right: '-' + operateWidth + 'px' }">
|
||||||
|
<slot name="button"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="isShowBtn && showMask" class="swipe-action_mask" @tap.stop="closeButtonGroup" @touchstart.stop.prevent="closeButtonGroup"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'riderSwipeAction',
|
||||||
|
emits: ['click'],
|
||||||
|
props: {
|
||||||
|
// name: '删除',
|
||||||
|
// color: '#fff',
|
||||||
|
// fontsize: 32,//单位rpx
|
||||||
|
// width: 80, //单位px
|
||||||
|
// icon: 'like.png',//此处为图片地址
|
||||||
|
// background: '#ed3f14'
|
||||||
|
actions: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//点击按钮时是否自动关闭
|
||||||
|
closable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//设为false,可以滑动多行不关闭菜单
|
||||||
|
showMask: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
operateWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: 80
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//禁止滑动
|
||||||
|
forbid: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//手动开关
|
||||||
|
open: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//背景色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
actions(newValue, oldValue) {
|
||||||
|
this.updateButtonSize();
|
||||||
|
},
|
||||||
|
open(newValue) {
|
||||||
|
this.manualSwitch(newValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
//start position
|
||||||
|
tStart: {
|
||||||
|
pageX: 0,
|
||||||
|
pageY: 0
|
||||||
|
},
|
||||||
|
//限制滑动距离
|
||||||
|
limitMove: 0,
|
||||||
|
//move position
|
||||||
|
position: {
|
||||||
|
pageX: 0,
|
||||||
|
pageY: 0
|
||||||
|
},
|
||||||
|
isShowBtn: false,
|
||||||
|
move: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateButtonSize();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
swipeDirection(x1, x2, y1, y2) {
|
||||||
|
return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : y1 - y2 > 0 ? 'Up' :
|
||||||
|
'Down';
|
||||||
|
},
|
||||||
|
//阻止事件冒泡
|
||||||
|
loop() {},
|
||||||
|
updateButtonSize() {
|
||||||
|
const actions = this.actions;
|
||||||
|
if (actions.length > 0) {
|
||||||
|
const query = uni.createSelectorQuery().in(this);
|
||||||
|
let limitMovePosition = 0;
|
||||||
|
actions.forEach(item => {
|
||||||
|
limitMovePosition += item.width || 0;
|
||||||
|
});
|
||||||
|
this.limitMove = limitMovePosition;
|
||||||
|
} else {
|
||||||
|
this.limitMove = this.operateWidth;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handlerTouchstart(event) {
|
||||||
|
if (this.forbid) return;
|
||||||
|
let touches = event.touches
|
||||||
|
if (touches && touches.length > 1) return;
|
||||||
|
this.move = true;
|
||||||
|
touches = touches ? event.touches[0] : {};
|
||||||
|
if (!touches || (touches.pageX === undefined && touches.pageY === undefined)) {
|
||||||
|
touches = {
|
||||||
|
pageX: event.pageX,
|
||||||
|
pageY: event.pageY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const tStart = this.tStart;
|
||||||
|
if (touches) {
|
||||||
|
for (let i in tStart) {
|
||||||
|
if (touches[i]) {
|
||||||
|
tStart[i] = touches[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
swipper(touches) {
|
||||||
|
const start = this.tStart;
|
||||||
|
const spacing = {
|
||||||
|
pageX: touches.pageX - start.pageX,
|
||||||
|
pageY: touches.pageY - start.pageY
|
||||||
|
};
|
||||||
|
if (this.limitMove < Math.abs(spacing.pageX)) {
|
||||||
|
spacing.pageX = -this.limitMove;
|
||||||
|
}
|
||||||
|
this.position = spacing;
|
||||||
|
// console.log('===', this.position )
|
||||||
|
},
|
||||||
|
handlerTouchmove(event) {
|
||||||
|
if (this.forbid || !this.move) return;
|
||||||
|
const start = this.tStart;
|
||||||
|
let touches = event.touches ? event.touches[0] : {};
|
||||||
|
if (!touches || (touches.pageX === undefined && touches.pageY === undefined)) {
|
||||||
|
touches = {
|
||||||
|
pageX: event.pageX,
|
||||||
|
pageY: event.pageY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (touches) {
|
||||||
|
const direction = this.swipeDirection(start.pageX, touches.pageX, start.pageY, touches.pageY);
|
||||||
|
if (direction === 'Left' && Math.abs(this.position.pageX) !== this.limitMove) {
|
||||||
|
this.swipper(touches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handlerTouchend(event) {
|
||||||
|
if (this.forbid || !this.move) return;
|
||||||
|
this.move = false;
|
||||||
|
const start = this.tStart;
|
||||||
|
let touches = event.changedTouches ? event.changedTouches[0] : {};
|
||||||
|
if (!touches || (touches.pageX === undefined && touches.pageY === undefined)) {
|
||||||
|
touches = {
|
||||||
|
pageX: event.pageX,
|
||||||
|
pageY: event.pageY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (touches) {
|
||||||
|
const direction = this.swipeDirection(start.pageX, touches.pageX, start.pageY, touches.pageY);
|
||||||
|
const spacing = {
|
||||||
|
pageX: touches.pageX - start.pageX,
|
||||||
|
pageY: touches.pageY - start.pageY
|
||||||
|
};
|
||||||
|
if (Math.abs(spacing.pageX) >= 40 && direction === 'Left') {
|
||||||
|
spacing.pageX = spacing.pageX < 0 ? -(this.limitMove + this.actions.length * 8 + 8) : this.limitMove;
|
||||||
|
this.isShowBtn = true;
|
||||||
|
} else {
|
||||||
|
spacing.pageX = 0;
|
||||||
|
}
|
||||||
|
if (spacing.pageX == 0) {
|
||||||
|
this.isShowBtn = false;
|
||||||
|
}
|
||||||
|
this.position = spacing;
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handlerButton(event) {
|
||||||
|
if (this.closable) {
|
||||||
|
this.closeButtonGroup();
|
||||||
|
}
|
||||||
|
const dataset = event.currentTarget.dataset;
|
||||||
|
this.$emit('click', {
|
||||||
|
index: Number(dataset.index),
|
||||||
|
item: this.params
|
||||||
|
});
|
||||||
|
},
|
||||||
|
closeButtonGroup() {
|
||||||
|
this.position = {
|
||||||
|
pageX: 0,
|
||||||
|
pageY: 0
|
||||||
|
};
|
||||||
|
this.isShowBtn = false;
|
||||||
|
},
|
||||||
|
//控制自定义按钮菜单
|
||||||
|
handlerParentButton(event) {
|
||||||
|
if (this.closable) {
|
||||||
|
this.closeButtonGroup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
manualSwitch(isOpen) {
|
||||||
|
let x = 0;
|
||||||
|
if (isOpen) {
|
||||||
|
if (this.actions.length === 0) {
|
||||||
|
x = this.operateWidth;
|
||||||
|
} else {
|
||||||
|
let width = 0;
|
||||||
|
this.actions.forEach(item => {
|
||||||
|
width += item.width;
|
||||||
|
});
|
||||||
|
x = width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.position = {
|
||||||
|
pageX: -x,
|
||||||
|
pageY: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
px(num) {
|
||||||
|
return uni.upx2px(num) + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.rider-swipeout-wrap {
|
||||||
|
width: 710rpx;
|
||||||
|
margin: 20rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swipe-action-show {
|
||||||
|
position: relative;
|
||||||
|
z-index: 998;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-swipeout-item {
|
||||||
|
width: 100%;
|
||||||
|
/* padding: 15px 20px; */
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-swipeout-content {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-swipeout-button-right-group {
|
||||||
|
position: absolute;
|
||||||
|
right: -100%;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 8px;
|
||||||
|
background: #f6f6f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-swipeout-button-right-item+.rider-swipeout-button-right-item {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-swipeout-button-right-item {
|
||||||
|
border-radius: 50%;
|
||||||
|
/* float: left; */
|
||||||
|
white-space: nowrap;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swipe-action_mask {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 997;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,624 @@
|
||||||
|
<template xlang="wxml">
|
||||||
|
<view class="rider-tree">
|
||||||
|
<view class="rider-tree-mask" :class="{ show: showTree }" @tap="_cancel"></view>
|
||||||
|
<view class="rider-tree-cnt" :class="{ show: showTree }">
|
||||||
|
<view class="rider-tree-bar">
|
||||||
|
<view class="rider-tree-bar-cancel" :style="{ color: cancelColor }" hover-class="hover-c" @tap="_cancel">取消</view>
|
||||||
|
<view class="rider-tree-bar-title" :style="{ color: titleColor }">{{ title }}</view>
|
||||||
|
<view class="rider-tree-bar-confirm" :style="{ color: confirmColor }" hover-class="hover-c" @tap="_confirm">确定</view>
|
||||||
|
</view>
|
||||||
|
<view class="rider-tree-view">
|
||||||
|
<scroll-view class="rider-tree-view-sc" :scroll-y="true">
|
||||||
|
<block v-for="(item, index) in treeList" :key="index">
|
||||||
|
<view
|
||||||
|
class="rider-tree-item"
|
||||||
|
:style="[{ paddingLeft: item.rank * 15 + 'px', zIndex: item.rank * -1 + 50 }]"
|
||||||
|
:class="{ show: item.show, last: item.lastRank, showchild: item.showChild, open: item.open }"
|
||||||
|
>
|
||||||
|
<view class="rider-tree-label" @tap.stop="onTreeItemTap(item, index)">
|
||||||
|
<image
|
||||||
|
class="rider-tree-icon"
|
||||||
|
:src="item.lastRank ? lastIcon : item.showChild ? currentIcon : defaultIcon"
|
||||||
|
></image>
|
||||||
|
{{ item.name }}
|
||||||
|
</view>
|
||||||
|
<view class="rider-tree-check" @tap.stop="onTreeItemSelect(item, index)" v-if="selectParent ? true : item.lastRank">
|
||||||
|
<view
|
||||||
|
class="rider-tree-check-yes"
|
||||||
|
v-if="item.checked"
|
||||||
|
:class="{ radio: !multiple }"
|
||||||
|
:style="{ 'border-color': confirmColor }"
|
||||||
|
>
|
||||||
|
<view class="rider-tree-check-yes-b" :style="{ 'background-color': confirmColor }"></view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="rider-tree-check-no"
|
||||||
|
v-else
|
||||||
|
:class="{ radio: !multiple }"
|
||||||
|
:style="{ 'border-color': confirmColor }"
|
||||||
|
></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'rider-tree',
|
||||||
|
props: {
|
||||||
|
range: {
|
||||||
|
type: Array,
|
||||||
|
default: function() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
idKey: {
|
||||||
|
//字段key值
|
||||||
|
type: String,
|
||||||
|
default: 'id'
|
||||||
|
},
|
||||||
|
nameKey: {
|
||||||
|
//字段value值
|
||||||
|
type: String,
|
||||||
|
default: 'name'
|
||||||
|
},
|
||||||
|
allKey: {
|
||||||
|
//冗余字段
|
||||||
|
type: String,
|
||||||
|
default: 'value'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
//头
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
// 是否可以多选
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
// default: true
|
||||||
|
},
|
||||||
|
cascade: {
|
||||||
|
// 是否级联选择
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
// default: true
|
||||||
|
},
|
||||||
|
selectParent: {
|
||||||
|
//是否可以选父级
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
foldAll: {
|
||||||
|
//折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
confirmColor: {
|
||||||
|
// 确定按钮颜色
|
||||||
|
type: String,
|
||||||
|
default: '' // #007aff
|
||||||
|
},
|
||||||
|
cancelColor: {
|
||||||
|
// 取消按钮颜色
|
||||||
|
type: String,
|
||||||
|
default: '' // #757575
|
||||||
|
},
|
||||||
|
titleColor: {
|
||||||
|
// 标题颜色
|
||||||
|
type: String,
|
||||||
|
default: '' // #757575
|
||||||
|
},
|
||||||
|
currentIcon: {
|
||||||
|
// 展开时候的ic
|
||||||
|
type: String,
|
||||||
|
default:
|
||||||
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEQ0QTM0MzQ1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEQ0QTM0MzU1Q0RBMTFFOUE0MjY4NzI1Njc1RjI1ODIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowRDRBMzQzMjVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowRDRBMzQzMzVDREExMUU5QTQyNjg3MjU2NzVGMjU4MiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PidwepsAAAK0SURBVHja7JxbTsJAFIYHww7ciStgCeoGvGxAiOsgURegoL5720AXYLiIr0aJviq3Zx3PhIEnKG3ndtr+f3KixrSUj/ZjzjClIqUUiFm2gAAQAREQEUAEREAERAQQAREQAREBREAEREBEEqa67h9RFDWllDv0awWYlqlQHmu1WjMRRMoV1QFttA12y3xRtdNczq8EsE4/f8FumX2q77ROvNXk8UGMEKdUz6tYJHljaZAbuyUH+UR1to5BEohTuqwPCeS4pAA/qY6o/kyHOAMCeRK3owJnj+rH1jjxhqpVsstaebCz6TmnHWyXyY+xHjSBWBY/bvSgadtXBj9u9KCN3rnIfkzkQVsTEEX0Y2IP2oKo/HhMICcFAThUcwVZNGU6FdbX/XURzkbVF4+ybGhjPrFdgP66QdXNurGtSdk6Xdb9nAJ8oDo3OQlsQZzkdPw41ONBo6vI5scDefRjZg+6gpg3Pxp50CXEvPjR2IOuIXL3oxUPuobI3Y9WPOgDIlc/WvOgL4iL/vqFCcD7LH0xB4hj7cfQ/fWH9qCT+FhG0tN+DBk1PzjOM0SVllixcsBT1AvYc/kAPhc0hRg/3uvxoCgKRN9+dOrBUBB9+9GpB0NC9OVH5x4MDdG1H714kANEV3705kEOEBf9dcPi/lQnsuvLg1wgSu3Ha0v7Uh4MMgUXeuG71H407a+VBy9CPQkOdw+MtB+nGbd/D+FBbhBNxo9SjwcngJjNj0E9yBFiFj8G9SBXiGn8GNyDnCEm8SMLD3KHGOdHNh7kDjHOj2w8mAeIi/5arX+c6b/fxHz9oADEdGdjR/fXCw/OOB5oVfCOgnepz8IB14PMw03jCmTE+QBx5z0gAmKSqK9OUF+hcAeIhu/QYr4Qie8rjW83hhMBERARQAREQAREBBABERCLnH8BBgA+TQI7U4t53AAAAABJRU5ErkJggg=='
|
||||||
|
},
|
||||||
|
defaultIcon: {
|
||||||
|
// 折叠时候的ic
|
||||||
|
type: String,
|
||||||
|
default:
|
||||||
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABRCAYAAACqj0o2AAACE0lEQVR4Xu3c200DMRCF4XEltJAOkEugA+ggpUAHoQMqiFMCdEAJUMEiS4mEELlIO7bPOeN9i6K1rG/952myyea1WiCtXmEuYBPR4RBMxInoIOCwhOtJLKVszWyXc/5y2BvNEq6I+/3+kFK6M7OHnPM7jcLKjbZAvD/uaZtzflm5P4rbWyJWgDcze1LPuzVihfxUz7sH4ilJ2bx7Isrm3RtRMu8RiHJ5j0SUyXs0okTeCIj0eSMh0uaNhkiZNyIiXd7IiDR5oyNS5M2ACJ83EyJs3myIkHkzIsLlzYwIkzc7IkTeCojD81ZCHJa3GuKQvBURu+etjNgtb3XELnlHQGyedyTEZnlHQ2ySd0RE97wjI7rlHR3RJe+JeIrbLOecD6ePpZQ6W1kn2epo4MUrPOKyLN8ppYq1+y1VStncOjIdGnFZlo+U0uOtWOeOY2TE12Ouq//pEA7xXL7XfvcufR8K0Svfv6CREN3yDYfYIt9QiK3yjYTYLF95xB75SiP2ylcZsVu+cogj8pVCHJWvEuKwfOkREfKlRkTJlxkRJl86RMR8qRBR82VChM0XHpEhX2hElnyREWnyhUNkzBcKkTVfJETafIcjKuQ7FFEl35GIMvl2R1TMtyuiar49EWXzbY5oZpv/hibXTF2h3+s60FRKeT6+3TjMS3nrA3ZFRD8xrfY3ER1kJ+JEdBBwWGKeRAfEH1wS5WFZSDB/AAAAAElFTkSuQmCC'
|
||||||
|
},
|
||||||
|
lastIcon: {
|
||||||
|
// 没有子集的ic
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showTree: false,
|
||||||
|
treeList: [],
|
||||||
|
selectIndex: -1,
|
||||||
|
returnedItem: [], //定义一个空数组
|
||||||
|
pids: [],
|
||||||
|
ancestorsIds: [],
|
||||||
|
childNums: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
methods: {
|
||||||
|
_show() {
|
||||||
|
this.showTree = true
|
||||||
|
},
|
||||||
|
_hide() {
|
||||||
|
this.showTree = false
|
||||||
|
},
|
||||||
|
_cancel() {
|
||||||
|
this._hide()
|
||||||
|
this.$emit('cancel', [])
|
||||||
|
},
|
||||||
|
_confirm() {
|
||||||
|
// 处理所选数据
|
||||||
|
let rt = [],
|
||||||
|
obj = {}
|
||||||
|
this.treeList.forEach((v, i) => {
|
||||||
|
if (this.treeList[i].checked) {
|
||||||
|
rt.push({
|
||||||
|
id: this.treeList[i].id,
|
||||||
|
name: this.treeList[i].name,
|
||||||
|
value: this.treeList[i].value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this._hide()
|
||||||
|
this.$emit('confirm', rt)
|
||||||
|
},
|
||||||
|
//扁平化树结构
|
||||||
|
_renderTreeList(list = [], rank = 0, parentId = [], parents = []) {
|
||||||
|
list.forEach(item => {
|
||||||
|
this.treeList.push({
|
||||||
|
id: item[this.idKey],
|
||||||
|
name: item[this.nameKey],
|
||||||
|
value: item[this.allKey],
|
||||||
|
source: item,
|
||||||
|
parentId, // 父级id数组
|
||||||
|
parents, // 父级id数组
|
||||||
|
rank, // 层级
|
||||||
|
showChild: false, //子级是否显示
|
||||||
|
open: false, //是否打开
|
||||||
|
show: rank === 0, // 自身是否显示
|
||||||
|
hideArr: [],
|
||||||
|
orChecked: item.checked ? item.checked : false,
|
||||||
|
checked: item.checked ? item.checked : false,
|
||||||
|
childNum: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(item.children) && item.children.length > 0) {
|
||||||
|
// console.log(item)
|
||||||
|
let parentid = [...parentId],
|
||||||
|
parentArr = [...parents]
|
||||||
|
delete parentArr.children
|
||||||
|
parentid.push(item[this.idKey])
|
||||||
|
parentArr.push({
|
||||||
|
[this.idKey]: item[this.idKey],
|
||||||
|
[this.nameKey]: item[this.nameKey],
|
||||||
|
[this.allKey]: item[this.allKey]
|
||||||
|
})
|
||||||
|
this._renderTreeList(item.children, rank + 1, parentid, parentArr)
|
||||||
|
} else {
|
||||||
|
this.treeList[this.treeList.length - 1].lastRank = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 处理默认选择
|
||||||
|
_defaultSelect() {
|
||||||
|
this.treeList.forEach((v, i) => {
|
||||||
|
if (v.checked) {
|
||||||
|
this.treeList.forEach((v2, i2) => {
|
||||||
|
if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) {
|
||||||
|
v2.show = true
|
||||||
|
if (v.parentId.includes(v2.id)) {
|
||||||
|
v2.showChild = true
|
||||||
|
v2.open = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getOwn(id, arr) {
|
||||||
|
//利用foreach循环遍历
|
||||||
|
arr.forEach(item => {
|
||||||
|
//判断递归结束条件
|
||||||
|
if (item[this.idKey] == id) {
|
||||||
|
// 存储数据到空数组
|
||||||
|
this.returnedItem = item
|
||||||
|
} else if (item.children != null) {
|
||||||
|
//判断chlidren是否有数据
|
||||||
|
//递归调用
|
||||||
|
this.getOwn(id, item.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return this.returnedItem
|
||||||
|
},
|
||||||
|
setShow(id, arr, isShow) {
|
||||||
|
arr.forEach((item, index) => {
|
||||||
|
if (item.parentId.includes(id)) {
|
||||||
|
this.treeList[index].showChild = isShow
|
||||||
|
this.treeList[index].show = isShow
|
||||||
|
} else if (item.children !== undefined) {
|
||||||
|
this.setShow(id, item.children, isShow)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 点击
|
||||||
|
onTreeItemTap(item, index) {
|
||||||
|
// console.log(item)
|
||||||
|
if (item.lastRank === true) {
|
||||||
|
//点击最后一级时触发事件
|
||||||
|
this.treeList[index].checked = !this.treeList[index].checked
|
||||||
|
this._fixMultiple(index)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let id = item.id
|
||||||
|
item.showChild = !item.showChild
|
||||||
|
// qingqian
|
||||||
|
if (item.showChild) {
|
||||||
|
const range = this.range
|
||||||
|
const parentIdArr = item.parentId
|
||||||
|
// 找到当前元素
|
||||||
|
const own = this.getOwn(id, range)
|
||||||
|
const checkedChildren = own.children
|
||||||
|
// 子元素插入的索引位置
|
||||||
|
const nextIndex = this.treeList.findIndex(itemT => itemT.id === item.id)
|
||||||
|
if (checkedChildren === undefined || checkedChildren.length < 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 子节点数量
|
||||||
|
this.treeList[index].childNum = checkedChildren.length
|
||||||
|
const newRank = item.rank + 1
|
||||||
|
checkedChildren.forEach(itemC => {
|
||||||
|
const childObj = {
|
||||||
|
id: itemC[this.idKey],
|
||||||
|
name: itemC[this.nameKey],
|
||||||
|
value: itemC[this.allKey],
|
||||||
|
source: {},
|
||||||
|
parentId: [item.id], // 父级id数组
|
||||||
|
parents: [item], // 父级id数组
|
||||||
|
rank: newRank, // 层级
|
||||||
|
showChild: false, //子级是否显示
|
||||||
|
open: false, //是否打开
|
||||||
|
show: 1, // 自身是否显示
|
||||||
|
hideArr: [],
|
||||||
|
lastRank: itemC.children && itemC.children.length > 0 ? false : true,
|
||||||
|
orChecked: this.treeList[index].checked,
|
||||||
|
checked: this.cascade ? this.treeList[index].checked : false
|
||||||
|
}
|
||||||
|
if (!this.treeList.some(itemT => itemT.id === itemC[this.idKey])) {
|
||||||
|
this.treeList.splice(nextIndex + 1, 0, childObj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 展开/隐藏子级/孙级
|
||||||
|
let list = this.treeList
|
||||||
|
item.open = item.showChild ? true : !item.open
|
||||||
|
list.forEach((childItem, i) => {
|
||||||
|
if (item.showChild === false) {
|
||||||
|
//隐藏所有子级
|
||||||
|
if (!childItem.parentId.includes(id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//TODO: 修改
|
||||||
|
if (!this.foldAll) {
|
||||||
|
if (childItem.lastRank !== true && !childItem.open) {
|
||||||
|
childItem.showChild = false
|
||||||
|
this.setShow(childItem.id, this.treeList, false)
|
||||||
|
}
|
||||||
|
// 为隐藏的内容添加一个标记
|
||||||
|
if (childItem.show) {
|
||||||
|
childItem.hideArr[item.rank] = id
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (childItem.lastRank !== true) {
|
||||||
|
childItem.showChild = false
|
||||||
|
// 继续隐藏子级的的子级
|
||||||
|
this.setShow(childItem.id, this.treeList, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (childItem.children !== undefined) {
|
||||||
|
childItem.children.forEach((childItem1, i1) => {
|
||||||
|
if (!childItem1.parentId.includes(childItem.id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
childItem.children[i1].showChild = false
|
||||||
|
childItem.children[i1].show = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
childItem.show = false
|
||||||
|
} else {
|
||||||
|
// 打开子集
|
||||||
|
if (childItem.parentId[childItem.parentId.length - 1] === id) {
|
||||||
|
childItem.show = true
|
||||||
|
}
|
||||||
|
// 打开被隐藏的子集
|
||||||
|
if (childItem.parentId.includes(id) && !this.foldAll) {
|
||||||
|
// console.log(childItem.hideArr)
|
||||||
|
if (childItem.hideArr[item.rank] === id) {
|
||||||
|
childItem.show = true
|
||||||
|
if (childItem.open && childItem.showChild) {
|
||||||
|
childItem.showChild = true
|
||||||
|
} else {
|
||||||
|
childItem.showChild = false
|
||||||
|
}
|
||||||
|
childItem.hideArr[item.rank] = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 通过父id处理子级
|
||||||
|
syncChecked(trees, pid, checked) {
|
||||||
|
trees.forEach((item, index) => {
|
||||||
|
if (item.parentId.includes(pid)) {
|
||||||
|
this.treeList[index].checked = checked
|
||||||
|
this.syncChecked(trees, item.id, checked)
|
||||||
|
} else if (item.children !== undefined) {
|
||||||
|
this.syncChecked(item.children, pid, checked)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取父级往上所有层级的id 并同步状态
|
||||||
|
setAncestors(pids, checked) {
|
||||||
|
this.treeList.forEach((item, index) => {
|
||||||
|
if (pids.includes(item.id)) {
|
||||||
|
if (checked && this.childNums[item.id] !== undefined && item.childNum === this.childNums[item.id]) {
|
||||||
|
// 子级全部选中, 父级才选中
|
||||||
|
this.treeList[index].checked = true
|
||||||
|
} else {
|
||||||
|
this.treeList[index].checked = false
|
||||||
|
}
|
||||||
|
this.setAncestors(item.parentId, checked)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onTreeItemSelect(item, index) {
|
||||||
|
this.treeList[index].checked = !this.treeList[index].checked
|
||||||
|
// 选父级, 子级自动全选
|
||||||
|
if (this.cascade) {
|
||||||
|
this.syncChecked(this.treeList, item.id, this.treeList[index].checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.rank > 0) {
|
||||||
|
item.parentId.forEach((pid, indexP) => {
|
||||||
|
const parent = this.treeList.filter(i => i.id === pid)
|
||||||
|
const childNum = parent.length > 0 ? parent[0].childNum : 0
|
||||||
|
if (this.childNums[pid] === undefined) {
|
||||||
|
this.childNums[pid] = 1
|
||||||
|
} else if (this.childNums[pid] < childNum) {
|
||||||
|
this.childNums[pid]++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//子级选择/选满/取消选择, 父级往上同步状态
|
||||||
|
if (this.cascade) {
|
||||||
|
this.setAncestors(item.parentId, this.treeList[index].checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._fixMultiple(index)
|
||||||
|
},
|
||||||
|
// 处理单选多选
|
||||||
|
_fixMultiple(index) {
|
||||||
|
if (!this.multiple) {
|
||||||
|
// 如果是单选
|
||||||
|
this.treeList.forEach((v, i) => {
|
||||||
|
if (i != index) {
|
||||||
|
this.treeList[i].checked = false
|
||||||
|
} else {
|
||||||
|
this.treeList[i].checked = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 重置数据
|
||||||
|
_reTreeList() {
|
||||||
|
this.treeList.forEach((v, i) => {
|
||||||
|
this.treeList[i].checked = v.orChecked
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_initTree(range = this.range) {
|
||||||
|
this.treeList = []
|
||||||
|
this._renderTreeList(range)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this._defaultSelect(range)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
range(list) {
|
||||||
|
this._initTree(list)
|
||||||
|
},
|
||||||
|
multiple() {
|
||||||
|
if (this.range.length) {
|
||||||
|
this._reTreeList()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectParent() {
|
||||||
|
if (this.range.length) {
|
||||||
|
this._reTreeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this._initTree()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.rider-tree-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0rpx;
|
||||||
|
right: 0rpx;
|
||||||
|
bottom: 0rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
z-index: 9998;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-mask.show {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-cnt {
|
||||||
|
position: fixed;
|
||||||
|
top: 0rpx;
|
||||||
|
right: 0rpx;
|
||||||
|
bottom: 0rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
z-index: 19999;
|
||||||
|
top: 15vh;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
transform: translateY(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-cnt.show {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
height: 72rpx;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
padding-right: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-bottom-width: 1rpx !important;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-color: #f5f5f5;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #757575;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-bar-confirm {
|
||||||
|
color: #007aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-view {
|
||||||
|
position: absolute;
|
||||||
|
top: 0rpx;
|
||||||
|
right: 0rpx;
|
||||||
|
bottom: 0rpx;
|
||||||
|
left: 0rpx;
|
||||||
|
top: 72rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
padding-top: 20rpx;
|
||||||
|
padding-right: 20rpx;
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-view-sc {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #757575;
|
||||||
|
line-height: 1;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 0.2s;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-item.show {
|
||||||
|
height: 80rpx;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-item.showchild:before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-item.last:before {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-icon {
|
||||||
|
width: 26rpx;
|
||||||
|
height: 26rpx;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-label {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-check {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-check-yes,
|
||||||
|
.rider-tree-check-no {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-top-left-radius: 20%;
|
||||||
|
border-top-right-radius: 20%;
|
||||||
|
border-bottom-right-radius: 20%;
|
||||||
|
border-bottom-left-radius: 20%;
|
||||||
|
border-top-width: 1rpx;
|
||||||
|
border-left-width: 1rpx;
|
||||||
|
border-bottom-width: 1rpx;
|
||||||
|
border-right-width: 1rpx;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #007aff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-check-yes-b {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-top-left-radius: 20%;
|
||||||
|
border-top-right-radius: 20%;
|
||||||
|
border-bottom-right-radius: 20%;
|
||||||
|
border-bottom-left-radius: 20%;
|
||||||
|
background-color: #007aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-check .radio {
|
||||||
|
border-top-left-radius: 50%;
|
||||||
|
border-top-right-radius: 50%;
|
||||||
|
border-bottom-right-radius: 50%;
|
||||||
|
border-bottom-left-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rider-tree-check .radio .rider-tree-check-yes-b {
|
||||||
|
border-top-left-radius: 50%;
|
||||||
|
border-top-right-radius: 50%;
|
||||||
|
border-bottom-right-radius: 50%;
|
||||||
|
border-bottom-left-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-c {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,475 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<!-- head -->
|
||||||
|
<view class="head-area" :style="{ height: `${headHeight}rpx` }">
|
||||||
|
<u-navbar
|
||||||
|
:is-fixed="false"
|
||||||
|
:border-bottom="false"
|
||||||
|
:is-back="true"
|
||||||
|
:custom-back="navBack"
|
||||||
|
:title="isWeixin ? '' : option.navTitle"
|
||||||
|
:back-icon-name="option.navBackIcon || 'arrow-leftward'"
|
||||||
|
back-icon-color="#fff"
|
||||||
|
back-icon-size="35"
|
||||||
|
:background="{ background: 'transparent' }"
|
||||||
|
title-color="#fff"
|
||||||
|
>
|
||||||
|
<view class="nav-title" v-if="isWeixin">{{ option.navTitle }}</view>
|
||||||
|
<view class="nav-right" slot="right" v-if="option.manageBtn" @click="manageSwitch = !manageSwitch">
|
||||||
|
{{ manageSwitch ? '完成' : '管理' }}
|
||||||
|
</view>
|
||||||
|
</u-navbar>
|
||||||
|
<view class="search-item" v-if="option.searchShow">
|
||||||
|
<u-search
|
||||||
|
placeholder="搜索内容"
|
||||||
|
v-model="searchValue"
|
||||||
|
@search="onSearch(searchValue)"
|
||||||
|
@clear="onSearch(searchValue)"
|
||||||
|
shape="square"
|
||||||
|
bg-color="#8EAAFF"
|
||||||
|
placeholder-color="#5470C4"
|
||||||
|
color="#fff"
|
||||||
|
search-icon-color="#ffffffE5"
|
||||||
|
:clearabled="true"
|
||||||
|
:show-action="false"
|
||||||
|
></u-search>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- head seat -->
|
||||||
|
<view :style="{ height: `${headHeight}rpx` }"></view>
|
||||||
|
<!-- list -->
|
||||||
|
<block v-if="data && data.length > 0">
|
||||||
|
<view class="" v-for="(item, index) in data" :key="index">
|
||||||
|
<crud-item
|
||||||
|
:ref="`crud-item${index}`"
|
||||||
|
:list="data"
|
||||||
|
:node="item"
|
||||||
|
:option="option"
|
||||||
|
:nodeIndex="index"
|
||||||
|
:checkList="checkList"
|
||||||
|
:checkShow="manageSwitch"
|
||||||
|
:random-num="randomNum"
|
||||||
|
></crud-item>
|
||||||
|
</view>
|
||||||
|
<view style="padding: 20rpx 0;"><slot name="loadmore"></slot></view>
|
||||||
|
</block>
|
||||||
|
<!-- foot -->
|
||||||
|
<block v-if="manageSwitch">
|
||||||
|
<view :style="[{ height: isFullSucreen ? '168rpx' : '100rpx' }]"></view>
|
||||||
|
<view class="foot flex" v-if="manageSwitch" :class="[isFullSucreen ? 'foot-ipx' : '']">
|
||||||
|
<checkbox-group @change="onCheckedAll">
|
||||||
|
<label class="well-check flex flex-c">
|
||||||
|
<checkbox
|
||||||
|
color="#fff"
|
||||||
|
style="transform: scale(0.7)"
|
||||||
|
value="allSelect"
|
||||||
|
:checked="checkedAll"
|
||||||
|
class="curdCheck"
|
||||||
|
></checkbox>
|
||||||
|
<text class="checkAll">全选 ({{ checkList.length }})</text>
|
||||||
|
</label>
|
||||||
|
</checkbox-group>
|
||||||
|
<view class=""><view class="foot-del-btn" @click="onRemove">删除</view></view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<!-- form -->
|
||||||
|
<u-popup
|
||||||
|
v-model="createShow"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
border-radius="14"
|
||||||
|
mode="bottom"
|
||||||
|
closeable
|
||||||
|
@close="onCreateClose"
|
||||||
|
:mask-close-able="false"
|
||||||
|
>
|
||||||
|
<view class="popup-head"><u-section :title="action" :right="false" line-color="#5f88ff"></u-section></view>
|
||||||
|
<scroll-view scroll-y="true" style="height: 68vh;">
|
||||||
|
<view class="form">
|
||||||
|
<block v-if="formType == 'uviewForm'">
|
||||||
|
<u-form :model="value" ref="uForm" :label-width="option.labelWidth || 160"><slot name="form"></slot></u-form>
|
||||||
|
</block>
|
||||||
|
<block v-else><slot name="form"></slot></block>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="form-btn">
|
||||||
|
<u-button
|
||||||
|
v-if="action != '查看'"
|
||||||
|
@click="onSubmit"
|
||||||
|
:loading="disabled"
|
||||||
|
shape="circle"
|
||||||
|
ripple
|
||||||
|
:custom-style="{ width: '100%', background: 'linear-gradient(90deg, #69b0ff, #5f88ff)', color: '#fff' }"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</u-button>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
<!-- addBtn -->
|
||||||
|
<movable-area class="movable-area">
|
||||||
|
<movable-view class="movable-view" :x="moveX" :y="moveY" direction="all">
|
||||||
|
<image src="@/static/images/crud/create.png" @click="onCreateOpen"></image>
|
||||||
|
</movable-view>
|
||||||
|
</movable-area>
|
||||||
|
<!-- empty -->
|
||||||
|
<slot name="empty">
|
||||||
|
<block v-if="data.length == 0">
|
||||||
|
<u-empty text="工作再忙,也要记得喝水~" margin-top="200" :src="require('@/static/images/crud/empty.png')"></u-empty>
|
||||||
|
</block>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import crudItem from './components/crud-item/index'
|
||||||
|
import { checkModel } from './util/tool.js'
|
||||||
|
import validate from './util/validate.js'
|
||||||
|
export default {
|
||||||
|
name: 'rider-crud',
|
||||||
|
components: { crudItem },
|
||||||
|
props: {
|
||||||
|
value: {}, // 表单
|
||||||
|
data: Array, // 列表
|
||||||
|
// 配置
|
||||||
|
option: {
|
||||||
|
type: Object,
|
||||||
|
default: {
|
||||||
|
column: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 表单类型
|
||||||
|
formType: {
|
||||||
|
type: String,
|
||||||
|
default: 'uviewForm'
|
||||||
|
},
|
||||||
|
// 返回事件
|
||||||
|
navBack: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
rules: {}, // 校验规则
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isFullSucreen: checkModel(),
|
||||||
|
moveX: 320, //添加按钮坐标
|
||||||
|
moveY: 580,
|
||||||
|
checkedAll: false, //全选
|
||||||
|
checkList: [], //选中值
|
||||||
|
createShow: false, //form弹窗
|
||||||
|
disabled: false, // 操作按钮
|
||||||
|
action: '新增',
|
||||||
|
searchValue: '',
|
||||||
|
isWeixin: false,
|
||||||
|
manageSwitch: false,
|
||||||
|
headHeight: 0,
|
||||||
|
randomNum: Math.round(Math.random() * 99999) // 随机数,防止uni.on重复调用
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
manageSwitch: {
|
||||||
|
handler(newVal, oldVal) {
|
||||||
|
this.checkList = []
|
||||||
|
this.checkedAll = false
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
'option.searchShow': {
|
||||||
|
handler(newVal, oldVal) {
|
||||||
|
const that = this
|
||||||
|
this.headHeight = newVal ? 192 : 98
|
||||||
|
// #ifndef H5
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: function(res) {
|
||||||
|
const statusBarHeight = Number(res.statusBarHeight) + Number(res.platform == 'ios' ? 44 : 48)
|
||||||
|
that.headHeight = newVal ? statusBarHeight + 192 : statusBarHeight + 98
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 通信事件
|
||||||
|
created() {
|
||||||
|
let that = this
|
||||||
|
uni.$on(`action${this.randomNum}`, ({ index }, i, list) => {
|
||||||
|
that.onActionClick({ index }, i, list)
|
||||||
|
})
|
||||||
|
uni.$on(`checked${this.randomNum}`, (e, id) => {
|
||||||
|
that.onChecked(e, id)
|
||||||
|
})
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.isWeixin = true
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
this.isWeixin = false
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setLazyLoad(func) {
|
||||||
|
this.option.lazyLoad = func
|
||||||
|
setTimeout(() => {
|
||||||
|
this.data.forEach((d, i) => {
|
||||||
|
this.$refs[`crud-item${i}`][0].setLazyLoad(func)
|
||||||
|
})
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选择
|
||||||
|
onChecked(e, id) {
|
||||||
|
const i = e.detail.value[0]
|
||||||
|
if (i) this.checkList.push(i)
|
||||||
|
else this.checkList.splice(this.checkList.findIndex(e => e === id), 1)
|
||||||
|
this.checkedAll = this.checkList.length === this.data.length
|
||||||
|
},
|
||||||
|
// 全选
|
||||||
|
onCheckedAll() {
|
||||||
|
if (!this.checkedAll) {
|
||||||
|
this.checkedAll = true
|
||||||
|
this.checkList = []
|
||||||
|
this.data.map(e => {
|
||||||
|
this.checkList.push(e.id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.checkedAll = false
|
||||||
|
this.checkList = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 元素点击
|
||||||
|
onClick(item, index) {
|
||||||
|
const action = { name: '查看' }
|
||||||
|
const data = JSON.parse(JSON.stringify(item))
|
||||||
|
this.$emit('input', data)
|
||||||
|
this.$emit('action-click', { index, data, actionIndex: -1, action, done: this.show })
|
||||||
|
this.action = action.name
|
||||||
|
},
|
||||||
|
// 底部删除
|
||||||
|
onRemove() {
|
||||||
|
if (this.checkList.length === 0) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请选择至少一条数据',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$emit('del', this.checkList.join(','))
|
||||||
|
},
|
||||||
|
// 打开弹窗
|
||||||
|
onCreateOpen() {
|
||||||
|
this.action = '新增'
|
||||||
|
this.$emit('action-click', { action: { name: this.action }, done: this.show })
|
||||||
|
},
|
||||||
|
// 关闭弹窗
|
||||||
|
onCreateClose() {
|
||||||
|
this.hide()
|
||||||
|
},
|
||||||
|
// 添加保存
|
||||||
|
onSubmit() {
|
||||||
|
this.disabled = true
|
||||||
|
const data = JSON.parse(JSON.stringify(this.value))
|
||||||
|
if (this.formType == 'uviewForm') {
|
||||||
|
// #ifdef MP
|
||||||
|
validate(this.value, this.rules)
|
||||||
|
.then(() => {
|
||||||
|
this.$emit('submit', data, this.action, this.unloading, this.hide)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.unloading()
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP
|
||||||
|
this.$refs.uForm.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
this.$emit('submit', data, this.action, this.unloading, this.hide)
|
||||||
|
} else {
|
||||||
|
this.unloading()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
} else {
|
||||||
|
validate(this.value, this.rules)
|
||||||
|
.then(() => {
|
||||||
|
debugger
|
||||||
|
this.$emit('submit', data, this.action, this.unloading, this.hide)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index }, i, list) {
|
||||||
|
let action
|
||||||
|
if (index == -1) action = { name: '查看' }
|
||||||
|
else action = this.option.actions[index]
|
||||||
|
const data = JSON.parse(JSON.stringify(list[i]))
|
||||||
|
if (['新增', '编辑', '查看'].includes(action.name)) this.$emit('input', data)
|
||||||
|
this.$emit('action-click', { index: i, data, actionIndex: index, action, done: this.show })
|
||||||
|
// this.action = action.name
|
||||||
|
this.$set(this, 'action', action.name)
|
||||||
|
},
|
||||||
|
|
||||||
|
//全选删除后回调
|
||||||
|
allCheckHide(val) {
|
||||||
|
if (this.checkedAll) this.manageSwitch = val
|
||||||
|
this.checkList = []
|
||||||
|
},
|
||||||
|
|
||||||
|
// 搜索
|
||||||
|
onSearch(val) {
|
||||||
|
this.$emit('search', val)
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
this.createShow = true
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.rules && this.$refs['uForm'] && typeof this.$refs['uForm'].setRules == 'function') {
|
||||||
|
this.$refs['uForm'].setRules(this.rules)
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.createShow = false
|
||||||
|
this.disabled = false
|
||||||
|
this.$emit('input', {})
|
||||||
|
this.$emit('update:readonly', false)
|
||||||
|
},
|
||||||
|
unloading() {
|
||||||
|
this.disabled = false
|
||||||
|
},
|
||||||
|
hideChildren() {
|
||||||
|
this.data.forEach((d, i) => {
|
||||||
|
this.$refs[`crud-item${i}`][0].hide()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-one {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-area {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 999;
|
||||||
|
width: 100%;
|
||||||
|
background: url('/static/images/head_bg.png') no-repeat center bottom;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
|
||||||
|
.nav-right {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-right: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-item {
|
||||||
|
padding: 0 30rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-h {
|
||||||
|
height: 200rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部 */
|
||||||
|
/* 适配 */
|
||||||
|
.foot-ipx {
|
||||||
|
bottom: 68rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foot-ipx::after {
|
||||||
|
content: ' ';
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0 !important;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 68rpx !important;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foot {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 99;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 26rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-top: 2px solid #eee;
|
||||||
|
|
||||||
|
&-del-btn {
|
||||||
|
width: 160rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
line-height: 64rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
// color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 34px;
|
||||||
|
// background: linear-gradient(180deg, #5f88ff, #69b0ff);
|
||||||
|
color: #f56c6c;
|
||||||
|
background: #fef0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
padding: 0 30rpx 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-head {
|
||||||
|
padding: 36rpx 30rpx;
|
||||||
|
border-bottom: 2rpx dashed #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-btn {
|
||||||
|
margin: 30rpx;
|
||||||
|
min-height: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movable-area {
|
||||||
|
height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
position: fixed;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.movable-view {
|
||||||
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
pointer-events: auto;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 96rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 判断是否全面屏
|
||||||
|
export function checkModel(isFlag) {
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: res => {
|
||||||
|
let model = res.model;
|
||||||
|
for (var i = 11; i < 30; i++) {
|
||||||
|
isFlag = (model.indexOf("iPhone X") > -1 || model.indexOf("iPhone " + i) > -1) ? true : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return isFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字典文本
|
||||||
|
export function getDicLabel(id, list, props = { label: 'dictValue', value: 'dictKey' }) {
|
||||||
|
if (!list) return {}
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
const item = list[i]
|
||||||
|
if (item[props.value] == id) return item[props.label]
|
||||||
|
if (item.children) return getDicLabel(id, item.children, props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
export default (form, rules) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (form && rules) {
|
||||||
|
let pass = true
|
||||||
|
a: for (let key in rules) {
|
||||||
|
let rule = rules[key]
|
||||||
|
if (Array.isArray(rule)) {
|
||||||
|
for (let i = 0; i < rule.length; i++) {
|
||||||
|
const result = validate(rule[i], form[key])
|
||||||
|
if (!result) {
|
||||||
|
pass = false
|
||||||
|
break a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const result = validate(rule, form[key])
|
||||||
|
if (!result) {
|
||||||
|
pass = false
|
||||||
|
break a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pass) resolve()
|
||||||
|
else reject()
|
||||||
|
} else {
|
||||||
|
reject('需校验的对象为空')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const validate = (rule, value) => {
|
||||||
|
let pass = true
|
||||||
|
if (rule && rule.pattern && !rule.pattern.test(value)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: rule.message || '校验失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
pass = false
|
||||||
|
} else if (rule && rule.required && !value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: rule.message || '校验失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
pass = false
|
||||||
|
}
|
||||||
|
return pass
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
scp -r ./unpackage/dist/build/h5/* root@127.0.0.1:/data/wwwroot/rider.bladex.vip
|
||||||
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
import {
|
||||||
|
clientId,
|
||||||
|
clientSecret
|
||||||
|
} from '@/common/setting'
|
||||||
|
import {
|
||||||
|
options
|
||||||
|
} from '@/http/config.js';
|
||||||
|
import {
|
||||||
|
Base64
|
||||||
|
} from '@/utils/base64.js';
|
||||||
|
import Request from '@/utils/luch-request/index.js';
|
||||||
|
const http = new Request(options);
|
||||||
|
http.interceptors.request.use((config) => { // 可使用async await 做异步操作
|
||||||
|
// 假设有token值需要在头部需要携带
|
||||||
|
let accessToken = uni.getStorageSync('accessToken');
|
||||||
|
if (accessToken) {
|
||||||
|
config.header['Blade-Auth'] = 'bearer ' + accessToken;
|
||||||
|
}
|
||||||
|
// 安全请求header
|
||||||
|
config.header['Blade-Requested-With'] = 'BladeHttpRequest';
|
||||||
|
// 客户端认证参数
|
||||||
|
config.header['Authorization'] = 'Basic ' + Base64.encode(clientId + ':' + clientSecret);
|
||||||
|
|
||||||
|
// #ifndef H5
|
||||||
|
let url = config.url
|
||||||
|
if (process.env.NODE_ENV == 'development' && !url.startsWith("http")) {
|
||||||
|
url = url.substring(url.indexOf('/api') + 4)
|
||||||
|
config.url = url
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 额外参数
|
||||||
|
// config.data = config.data || {};
|
||||||
|
// config.data.pf = uni.getSystemInfoSync().platform;
|
||||||
|
// config.data.sys = uni.getSystemInfoSync().system;
|
||||||
|
|
||||||
|
// 演示custom 用处
|
||||||
|
// if (config.custom.auth) {
|
||||||
|
// config.header.token = 'token'
|
||||||
|
// }
|
||||||
|
// if (config.custom.loading) {
|
||||||
|
// uni.showLoading()
|
||||||
|
// }
|
||||||
|
/**
|
||||||
|
/* 演示
|
||||||
|
if (!token) { // 如果token不存在,return Promise.reject(config) 会取消本次请求
|
||||||
|
return Promise.reject(config)
|
||||||
|
}
|
||||||
|
**/
|
||||||
|
return config
|
||||||
|
}, config => { // 可使用async await 做异步操作
|
||||||
|
return Promise.reject(config)
|
||||||
|
})
|
||||||
|
http.interceptors.response.use((response) => {
|
||||||
|
// 若有数据返回则通过
|
||||||
|
if (response.data.access_token || response.data.key) {
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
// 服务端返回的状态码不等于200,则reject()
|
||||||
|
if (response.data.code !== 200) {
|
||||||
|
uni.showToast({
|
||||||
|
title: response.data.msg,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return Promise.reject(response);
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
}, (response) => {
|
||||||
|
/* 对响应错误做点什么 (statusCode !== 200)*/
|
||||||
|
uni.showToast({
|
||||||
|
title: response.data.msg,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
if (response.statusCode == 401) {
|
||||||
|
const pages = getCurrentPages()
|
||||||
|
const currentPage = pages[pages.length - 1]
|
||||||
|
uni.redirectTo({
|
||||||
|
url: `/pages/login/login-account?redirect=/${currentPage.route}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Promise.reject(response)
|
||||||
|
})
|
||||||
|
export default http;
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import {
|
||||||
|
devUrl,
|
||||||
|
prodUrl,
|
||||||
|
contentType
|
||||||
|
} from '@/common/setting'
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
baseURL: process.env.NODE_ENV === 'development' ? devUrl : prodUrl,
|
||||||
|
header: {
|
||||||
|
'Content-Type': contentType
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
// #ifndef MP-ALIPAY || APP-PLUS
|
||||||
|
responseType: 'text',
|
||||||
|
// #endif
|
||||||
|
// 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部)
|
||||||
|
custom: {}, // 全局自定义参数默认值
|
||||||
|
// #ifdef MP-ALIPAY || MP-WEIXIN
|
||||||
|
timeout: 30000,
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
sslVerify: true,
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
// 跨域请求时是否携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+)
|
||||||
|
//withCredentials: false,
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
firstIpv4: false, // DNS解析时优先使用ipv4 仅 App-Android 支持 (HBuilderX 2.8.0+)
|
||||||
|
// #endif
|
||||||
|
// 局部优先级高于全局,返回当前请求的task,options。请勿在此处修改options。非必填
|
||||||
|
// getTask: (task, options) => {
|
||||||
|
// 相当于设置了请求超时时间500ms
|
||||||
|
// setTimeout(() => {
|
||||||
|
// task.abort()
|
||||||
|
// }, 500)
|
||||||
|
// },
|
||||||
|
// 全局自定义验证器。参数为statusCode 且必存在,不用判断空情况。
|
||||||
|
// validateStatus: (statusCode) => { // statusCode 必存在。此处示例为全局默认配置
|
||||||
|
// return statusCode >= 200 && statusCode < 300
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
export { options };
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// 获取api目录所有js文件
|
||||||
|
const files = require.context('@/api', false, /\.js$/)
|
||||||
|
// 此处第二个参数vm,就是我们在页面使用的this,可以通过vm获取vuex等操作
|
||||||
|
const install = (Vue, vm) => {
|
||||||
|
// 将各个定义的接口名称,统一放进对象挂载到vm.$u.api下(因为vm就是this,也即this.$u.api)
|
||||||
|
// 自动将所有api挂载到vm.$u.api中
|
||||||
|
vm.$u.api = {}
|
||||||
|
files.keys().forEach(key => {
|
||||||
|
const api = files(key).default
|
||||||
|
for (let item in api) {
|
||||||
|
vm.$u.api[item] = api[item]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App'
|
||||||
|
import store from '@/store';
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
|
App.mpType = 'app';
|
||||||
|
|
||||||
|
// 引入全局uView
|
||||||
|
import uView from 'uview-ui'
|
||||||
|
Vue.use(uView);
|
||||||
|
|
||||||
|
// 引入vuex
|
||||||
|
const vuexStore = require("@/store/$u.mixin.js");
|
||||||
|
Vue.mixin(vuexStore);
|
||||||
|
|
||||||
|
// 创建对象
|
||||||
|
const app = new Vue({
|
||||||
|
store,
|
||||||
|
...App
|
||||||
|
});
|
||||||
|
|
||||||
|
// 接口集中管理
|
||||||
|
import httpInstall from '@/http/install.js'
|
||||||
|
Vue.use(httpInstall, app)
|
||||||
|
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
Vue.prototype.$http = http
|
||||||
|
|
||||||
|
// 公共函数
|
||||||
|
import globalFunc from '@/utils/func.js'
|
||||||
|
Vue.use(globalFunc, app);
|
||||||
|
|
||||||
|
app.$mount()
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
{
|
||||||
|
"name": "住房保障预约",
|
||||||
|
"appid": "__UNI__8FD82FF",
|
||||||
|
"description": "",
|
||||||
|
"versionName": "2.0.0",
|
||||||
|
"versionCode": "100",
|
||||||
|
"transformPx": false,
|
||||||
|
/* 5+App特有相关 */
|
||||||
|
"app-plus": {
|
||||||
|
"safearea": {
|
||||||
|
"bottom": {
|
||||||
|
"offset": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"usingComponents": true,
|
||||||
|
"nvueCompiler": "uni-app",
|
||||||
|
"compilerVersion": 3,
|
||||||
|
"splashscreen": {
|
||||||
|
"alwaysShowBeforeRender": true,
|
||||||
|
"waiting": true,
|
||||||
|
"autoclose": true,
|
||||||
|
"delay": 0
|
||||||
|
},
|
||||||
|
/* 模块配置 */
|
||||||
|
"modules": {},
|
||||||
|
/* 应用发布信息 */
|
||||||
|
"distribute": {
|
||||||
|
/* android打包配置 */
|
||||||
|
"android": {
|
||||||
|
"permissions": [
|
||||||
|
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||||
|
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
/* ios打包配置 */
|
||||||
|
"ios": {},
|
||||||
|
/* SDK配置 */
|
||||||
|
"sdkConfigs": {
|
||||||
|
"ad": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 快应用特有相关 */
|
||||||
|
"quickapp": {},
|
||||||
|
/* 小程序特有相关 */
|
||||||
|
"mp-weixin": {
|
||||||
|
"appid": "wxa79f37f7f9375f47",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": false,
|
||||||
|
"minified": true,
|
||||||
|
"postcss": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"usingComponents": true,
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mp-alipay": {
|
||||||
|
"usingComponents": true,
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mp-baidu": {
|
||||||
|
"usingComponents": true,
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mp-toutiao": {
|
||||||
|
"usingComponents": true,
|
||||||
|
"setting": {
|
||||||
|
"es6": true,
|
||||||
|
"minified": true,
|
||||||
|
"postcss": true,
|
||||||
|
"urlCheck": false
|
||||||
|
},
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"h5": {
|
||||||
|
"template": "template.h5.html",
|
||||||
|
"publicPath": "/housingAssuranceBookingMobile/",
|
||||||
|
"router": {
|
||||||
|
"mode": "hash",
|
||||||
|
"base": "/housingAssuranceBookingMobile"
|
||||||
|
},
|
||||||
|
"optimization": {
|
||||||
|
"treeShaking": {
|
||||||
|
"enable": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devServer": {
|
||||||
|
"proxy": {
|
||||||
|
"/api": {
|
||||||
|
"target": "http://192.168.3.111:8181",
|
||||||
|
// "target" : "http://192.168.3.100:2891",
|
||||||
|
//"target" : "https://rider.bladex.vip/api",
|
||||||
|
"pathRewrite": {
|
||||||
|
"^/api": "/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/epoint-web-cs": {
|
||||||
|
"target": "https://gxqzzfbzzx.cn",
|
||||||
|
"pathRewrite": {
|
||||||
|
"^/epoint-web-cs": "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"port": ""
|
||||||
|
},
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"sdkConfigs": {
|
||||||
|
"maps": {
|
||||||
|
"qqmap": {
|
||||||
|
"key": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
},
|
||||||
|
"mp-qq": {
|
||||||
|
"uniStatistics": {
|
||||||
|
"enable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"id": "ba-tree-picker",
|
||||||
|
"displayName": "ba-tree-picker树形层级选择器(支持单选、多选、父级选择、映射)",
|
||||||
|
"version": "1.2",
|
||||||
|
"description": "树形层级选择器,支持单选、多选、父级选择 、Object对象属性自定义映射、自定义样式等,采用弹窗形式,样式和比例参照uniapp官方的picker和uni-data-picker组件",
|
||||||
|
"keywords": [
|
||||||
|
"选择器",
|
||||||
|
"树形",
|
||||||
|
"层级",
|
||||||
|
"多选",
|
||||||
|
"ba-tree-picker"
|
||||||
|
],
|
||||||
|
"dcloudext": {
|
||||||
|
"category": [
|
||||||
|
"前端组件",
|
||||||
|
"通用组件"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
{
|
||||||
|
"easycom": {
|
||||||
|
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue",
|
||||||
|
"^wf-(.*)": "@/components/wf-ui/components/wf-$1/wf-$1.vue"
|
||||||
|
},
|
||||||
|
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
||||||
|
{
|
||||||
|
"path": "pages/loading/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "云预约",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/home/home",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "云预约",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/reserve/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "网上预约",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/reserve/notice",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "预约须知",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/reserve/timeSelect",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "预约时间",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/reserve/confirm",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "预约确认",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/myReserve/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的预约",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/myReserve/detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "预约详情",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"path": "pages/login/login-phone",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "手机登录",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
|
||||||
|
}, {
|
||||||
|
"path": "pages/login/login-account",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "账号登录",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"globalStyle": {
|
||||||
|
"navigationBarTextStyle": "black",
|
||||||
|
"navigationBarTitleText": "",
|
||||||
|
"navigationBarBackgroundColor": "#fff",
|
||||||
|
"backgroundColor": "#F7F7F7"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }" title="CRUD 操作"
|
||||||
|
title-color="#fff">
|
||||||
|
</u-navbar>
|
||||||
|
<view class="u-demo">
|
||||||
|
<view class="u-demo-wrap">
|
||||||
|
<view class="u-demo-title">很快到来</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,441 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
formType="uniForm"
|
||||||
|
@search="onSearch"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<view class="uni-form">
|
||||||
|
<view class="uni-form-item">
|
||||||
|
<view class="uni-form-item-label uni-form-item-required">通知标题</view>
|
||||||
|
<view class="uni-form-item-input">
|
||||||
|
<input
|
||||||
|
class="uni-input"
|
||||||
|
v-model="form.title"
|
||||||
|
placeholder="通知标题"
|
||||||
|
:placeholder-style="placeholderStyle"
|
||||||
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="uni-form-item">
|
||||||
|
<view class="uni-form-item-label uni-form-item-required">通知类型</view>
|
||||||
|
<view class="uni-form-item-input">
|
||||||
|
<picker
|
||||||
|
@change="e => onConfirm(e, 'category')"
|
||||||
|
:range="categoryList"
|
||||||
|
range-key="dictValue"
|
||||||
|
class="curdPicker"
|
||||||
|
:disabled="readonly"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="uni-input"
|
||||||
|
v-model="formLabel.category"
|
||||||
|
disabled
|
||||||
|
placeholder="通知类型"
|
||||||
|
:placeholder-style="placeholderStyle"
|
||||||
|
/>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
<view class="uni-form-item-icon"><u-icon name="arrow-right" color="#999" size="28"></u-icon></view>
|
||||||
|
</view>
|
||||||
|
<view class="uni-form-item">
|
||||||
|
<view class="uni-form-item-label uni-form-item-required">通知日期</view>
|
||||||
|
<view class="uni-form-item-input">
|
||||||
|
<picker
|
||||||
|
@change="e => onConfirm(e, 'releaseTime')"
|
||||||
|
mode="date"
|
||||||
|
:value="form.releaseTime"
|
||||||
|
:start="startDate"
|
||||||
|
:end="endDate"
|
||||||
|
class="curdPicker"
|
||||||
|
:disabled="readonly"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="uni-input"
|
||||||
|
v-model="form.releaseTime"
|
||||||
|
disabled
|
||||||
|
placeholder="通知日期"
|
||||||
|
:placeholder-style="placeholderStyle"
|
||||||
|
/>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
<view class="uni-form-item-icon"><u-icon name="arrow-right" color="#999" size="28"></u-icon></view>
|
||||||
|
</view>
|
||||||
|
<view class="uni-form-item">
|
||||||
|
<view class="uni-form-item-label">通知内容</view>
|
||||||
|
<view v-if="!readonly" class="uni-form-item-btn" @click="onRichEdit(form.content)">去编辑</view>
|
||||||
|
</view>
|
||||||
|
<mp-html :content="form.content"></mp-html>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import mpHtml from '@/components/rider-crud/components/mp-html/mp-html'
|
||||||
|
import { getList, add, update, remove } from '@/api/notice.js'
|
||||||
|
import { dictionary } from '@/api/system/dict.js'
|
||||||
|
import { logo } from '../../common/setting'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd, mpHtml },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
content: ''
|
||||||
|
},
|
||||||
|
formLabel: {
|
||||||
|
category: '' ,
|
||||||
|
},
|
||||||
|
list: [],
|
||||||
|
params: {
|
||||||
|
current: 1,
|
||||||
|
size: 10
|
||||||
|
},
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
labelWidth: 160,
|
||||||
|
placeholderStyle: 'color:rgb(192, 196, 204); font-size:14px',
|
||||||
|
option: {
|
||||||
|
navTitle: 'CRUD 操作', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '通知标题',
|
||||||
|
prop: 'title'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通知类型',
|
||||||
|
prop: 'categoryName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通知日期',
|
||||||
|
prop: 'releaseTime'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
title: [{ required: true, message: '请输入通知标题', trigger: 'blur' }],
|
||||||
|
category: [{ required: true, message: '请选择通知类型', trigger: 'change', type: 'number' }],
|
||||||
|
releaseTime: [{ required: true, message: '请选择通知日期', trigger: 'change' }]
|
||||||
|
},
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
checkedSwitch: false,
|
||||||
|
timeShow: false,
|
||||||
|
timeParams: {
|
||||||
|
year: true,
|
||||||
|
month: true,
|
||||||
|
day: true,
|
||||||
|
hour: true,
|
||||||
|
minute: true,
|
||||||
|
second: true
|
||||||
|
},
|
||||||
|
categoryShow: false,
|
||||||
|
categoryList: [], //类型
|
||||||
|
category: '',
|
||||||
|
pagesTotal: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
startDate() {
|
||||||
|
return this.getDate('start')
|
||||||
|
},
|
||||||
|
endDate() {
|
||||||
|
return this.getDate('end')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
let that = this
|
||||||
|
uni.$on('richBack', function(data) {
|
||||||
|
that.$set(that.form, 'content', data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.getList(true)
|
||||||
|
this.getCategoryList()
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDate(type) {
|
||||||
|
const date = new Date()
|
||||||
|
let year = date.getFullYear()
|
||||||
|
let month = date.getMonth() + 1
|
||||||
|
let day = date.getDate()
|
||||||
|
if (type === 'start') {
|
||||||
|
year = year - 60
|
||||||
|
} else {
|
||||||
|
year = year + 2
|
||||||
|
}
|
||||||
|
month = month > 9 ? month : '0' + month
|
||||||
|
day = day > 9 ? day : '0' + day
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
},
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
getList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const { records, current } = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.list = records
|
||||||
|
} else {
|
||||||
|
this.list = this.list.concat(records)
|
||||||
|
}
|
||||||
|
this.params.current++
|
||||||
|
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 通知类型
|
||||||
|
getCategoryList() {
|
||||||
|
dictionary({ code: 'notice' }).then(res => {
|
||||||
|
this.categoryList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// picker确定
|
||||||
|
onConfirm(e, type) {
|
||||||
|
if (type == 'category') {
|
||||||
|
const i = this.categoryList[e.detail.value]
|
||||||
|
this.$set(this.formLabel, type, i.dictValue)
|
||||||
|
this.$set(this.form, type, Number(i.dictKey))
|
||||||
|
} else {
|
||||||
|
this.$set(this.form, type, `${e.detail.value} 12:00:00`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 编辑富文本
|
||||||
|
onRichEdit(e) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/rich/index?data=${e}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
title: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
this.formLabel = { category: '' }
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
this.formLabel.category = getDicLabel(data.category, this.categoryList)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = { category: '' }
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = { category: '' }
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-picker-container {
|
||||||
|
z-index: 99999 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-right {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-right: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-form {
|
||||||
|
&-item {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
line-height: 70rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&-label {
|
||||||
|
width: 160rpx;
|
||||||
|
|
||||||
|
.required {
|
||||||
|
color: #fa3534;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-required {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: '*';
|
||||||
|
position: absolute;
|
||||||
|
left: -8px;
|
||||||
|
color: #fa3534;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-input {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.uni-input {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-btn {
|
||||||
|
color: #fff;
|
||||||
|
width: auto;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 50rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
background: linear-gradient(rgb(95, 136, 255), rgb(105, 176, 255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item:after {
|
||||||
|
content: ' ';
|
||||||
|
border-bottom-width: 2rpx;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-transform-origin: 0 0;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
width: 199.8%;
|
||||||
|
height: 199.7%;
|
||||||
|
-webkit-transform: scale(0.5, 0.5);
|
||||||
|
transform: scale(0.5, 0.5);
|
||||||
|
border: 0 solid #e4e7ed;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item:after {
|
||||||
|
border-bottom-width: 2rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,326 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@search="onSearch"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<view slot="form">
|
||||||
|
<u-form-item label="通知标题" prop="title" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.title" :disabled="readonly" placeholder="通知标题" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="通知类型" prop="category" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-model="formLabel.category"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="通知类型"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) categoryShow = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="通知日期" prop="releaseTime" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-model="form.releaseTime"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="通知日期"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) timeShow = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="通知内容" :label-width="option.labelWidth || 160" :border-bottom="false">
|
||||||
|
<template #right v-if="!readonly">
|
||||||
|
<u-button
|
||||||
|
@click="onRichEdit(form.content)"
|
||||||
|
ripple
|
||||||
|
:custom-style="{ background: '#FFF6E9', color: '#FAA646' }"
|
||||||
|
size="mini"
|
||||||
|
>
|
||||||
|
去编辑
|
||||||
|
</u-button>
|
||||||
|
</template>
|
||||||
|
</u-form-item>
|
||||||
|
<mp-html :content="form.content"></mp-html>
|
||||||
|
</view>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
<!-- 通知类型 -->
|
||||||
|
<u-select
|
||||||
|
v-model="categoryShow"
|
||||||
|
:list="categoryList"
|
||||||
|
value-name="dictKey"
|
||||||
|
label-name="dictValue"
|
||||||
|
@confirm="e => onConfirm(e, 'category')"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
></u-select>
|
||||||
|
<!-- 通知日期 -->
|
||||||
|
<u-picker
|
||||||
|
mode="time"
|
||||||
|
v-model="timeShow"
|
||||||
|
:params="timeParams"
|
||||||
|
start-year="2000"
|
||||||
|
end-year="2050"
|
||||||
|
@confirm="e => onConfirm(e, 'releaseTime')"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
></u-picker>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import mpHtml from '@/components/rider-crud/components/mp-html/mp-html'
|
||||||
|
import { getList, add, update, remove } from '@/api/notice.js'
|
||||||
|
import { dictionary } from '@/api/system/dict.js'
|
||||||
|
import { logo } from '../../common/setting'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd, mpHtml },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
checkedSwitch: false, // 默认打开管理
|
||||||
|
form: { content: '' }, // 表单
|
||||||
|
formLabel: {}, // 表单label
|
||||||
|
list: [], // 列表数据
|
||||||
|
params: {
|
||||||
|
// 分页
|
||||||
|
current: 1,
|
||||||
|
size: 10
|
||||||
|
},
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
option: {
|
||||||
|
// 组件选项
|
||||||
|
navTitle: '通知公告', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '通知标题',
|
||||||
|
prop: 'title'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通知类型',
|
||||||
|
prop: 'categoryName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通知日期',
|
||||||
|
prop: 'releaseTime'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
// 左滑操作按钮
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// 表单校验规则
|
||||||
|
title: [{ required: true, message: '请输入通知标题', trigger: 'blur' }],
|
||||||
|
category: [{ required: true, message: '请选择通知类型', trigger: 'change', type: 'number' }],
|
||||||
|
releaseTime: [{ required: true, message: '请选择通知日期', trigger: 'change' }]
|
||||||
|
},
|
||||||
|
timeShow: false,
|
||||||
|
timeParams: {
|
||||||
|
year: true,
|
||||||
|
month: true,
|
||||||
|
day: true,
|
||||||
|
hour: true,
|
||||||
|
minute: true,
|
||||||
|
second: true
|
||||||
|
},
|
||||||
|
categoryShow: false,
|
||||||
|
categoryList: [] //类型
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
let that = this
|
||||||
|
uni.$on('richBack', function(data) {
|
||||||
|
that.$set(that.form, 'content', data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.getList(true)
|
||||||
|
this.getCategoryList()
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
getList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const { records, current } = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.list = records
|
||||||
|
} else {
|
||||||
|
this.list = this.list.concat(records)
|
||||||
|
}
|
||||||
|
this.params.current++
|
||||||
|
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 通知类型
|
||||||
|
getCategoryList() {
|
||||||
|
dictionary({ code: 'notice' }).then(res => {
|
||||||
|
this.categoryList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 类型回调
|
||||||
|
onConfirm(e, type) {
|
||||||
|
if (type == 'category') {
|
||||||
|
this.formLabel[type] = e[0].label
|
||||||
|
this.form.category = Number(e[0].value)
|
||||||
|
} else {
|
||||||
|
this.$set(this.form, 'releaseTime', e.year + '-' + e.month + '-' + e.day + ' ' + e.hour + ':' + e.minute + ':' + e.second)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 编辑富文本
|
||||||
|
onRichEdit(e) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/rich/index?data=${e}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
title: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
this.formLabel = {}
|
||||||
|
this.form = { content: '' }
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
this.formLabel.category = getDicLabel(data.category, this.categoryList)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = {}
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = {}
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
export default [{
|
||||||
|
groupName: '基础功能',
|
||||||
|
list: [{
|
||||||
|
path: '/pages/demo/storage',
|
||||||
|
icon: 'cell',
|
||||||
|
title: 'Storage 操作',
|
||||||
|
}, {
|
||||||
|
path: '/pages/demo/vuex',
|
||||||
|
icon: 'sticky',
|
||||||
|
title: 'Vuex 操作',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupName: '网络功能',
|
||||||
|
list: [{
|
||||||
|
path: '/pages/demo/mock',
|
||||||
|
icon: 'layout',
|
||||||
|
title: 'Mock 调用',
|
||||||
|
}, {
|
||||||
|
path: '/pages/demo/request',
|
||||||
|
icon: 'tabbar',
|
||||||
|
title: 'API 调用',
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
groupName: '业务功能',
|
||||||
|
list: [{
|
||||||
|
path: '/pages/demo/crud1',
|
||||||
|
icon: 'tag',
|
||||||
|
title: 'CRUD 操作(基于Uniapp)',
|
||||||
|
},{
|
||||||
|
path: '/pages/demo/crud2',
|
||||||
|
icon: 'tag',
|
||||||
|
title: 'CRUD 操作(基于Uview)',
|
||||||
|
},{
|
||||||
|
path: '/pages/componentsA/parse/index',
|
||||||
|
icon: 'loading',
|
||||||
|
title: '未完待续',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<view class="wrap">
|
||||||
|
<page-nav :desc="desc" :title="title"></page-nav>
|
||||||
|
<view class="list-wrap">
|
||||||
|
<u-cell-group title-bg-color="rgb(243, 244, 246)" :title="getGroupTitle(item)" v-for="(item, index) in list"
|
||||||
|
:key="index">
|
||||||
|
<u-cell-item :titleStyle="{fontWeight: 500}" @click="openPage(item1.path)" :title="getFieldTitle(item1)"
|
||||||
|
v-for="(item1, index1) in item.list" :key="index1">
|
||||||
|
<image slot="icon" class="u-cell-icon" :src="getIcon(item1.icon)" mode="widthFix"></image>
|
||||||
|
</u-cell-item>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
<u-gap height="70"></u-gap>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import pageNav from '@/components/page-nav/page-nav.vue';
|
||||||
|
import list from "./demo.config.js";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
pageNav
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: list,
|
||||||
|
title: '基础功能示例合集',
|
||||||
|
desc: '众多示例覆盖开发过程的各个需求,正在不断完善中。可让您快速集成,开箱即用。'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
getIcon() {
|
||||||
|
return path => {
|
||||||
|
return 'https://cdn.uviewui.com/uview/example/' + path + '.png';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: "233"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openPage(path) {
|
||||||
|
this.$u.route({
|
||||||
|
url: path
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getGroupTitle(item) {
|
||||||
|
return item.groupName
|
||||||
|
},
|
||||||
|
getFieldTitle(item) {
|
||||||
|
return item.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* page {
|
||||||
|
background-color: rgb(240, 242, 244);
|
||||||
|
} */
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.u-cell-icon {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }" title="Mock 调用"
|
||||||
|
title-color="#fff">
|
||||||
|
</u-navbar>
|
||||||
|
<view class="u-demo">
|
||||||
|
<view class="u-demo-wrap">
|
||||||
|
<view class="u-demo-title">演示效果</view>
|
||||||
|
<view class="u-demo-area u-flex u-row-center">
|
||||||
|
数据为:{{data}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-config-wrap">
|
||||||
|
<view class="u-config-title u-border-bottom">参数操作</view>
|
||||||
|
<view class="u-config-item">
|
||||||
|
<view class="u-item-title">按钮点击</view>
|
||||||
|
<u-button @click="doRequest">获取数据</u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
fakeBannerList
|
||||||
|
} from "@/api/mock/home.js";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doRequest() {
|
||||||
|
let keyword = "";
|
||||||
|
fakeBannerList().then(data => {
|
||||||
|
this.data = data;
|
||||||
|
this.$u.func.showToast({
|
||||||
|
title: '数据获取成功',
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }" title="API 请求"
|
||||||
|
title-color="#fff">
|
||||||
|
</u-navbar>
|
||||||
|
<view class="u-demo">
|
||||||
|
<view class="u-demo-wrap">
|
||||||
|
<view class="u-demo-title">演示效果</view>
|
||||||
|
<view class="u-demo-area u-flex u-row-center">
|
||||||
|
<u-image width="300rpx" height="100rpx" :src="url"></u-image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-config-wßrap">
|
||||||
|
<view class="u-config-title u-border-bottom">参数操作</view>
|
||||||
|
<view class="u-config-item">
|
||||||
|
<view class="u-item-title">按钮点击</view>
|
||||||
|
<u-button @click="doRequest">刷新验证码</u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
url: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doRequest() {
|
||||||
|
let keyword = "";
|
||||||
|
// 自动挂载至this.$u.api,无需引入
|
||||||
|
// captcha 在 /api/demo.js 内定义
|
||||||
|
this.$u.api.captcha().then(data => {
|
||||||
|
this.url = data.image;
|
||||||
|
this.$u.func.showToast({
|
||||||
|
title: '数据获取成功',
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }" title="Storage 操作"
|
||||||
|
title-color="#fff">
|
||||||
|
</u-navbar>
|
||||||
|
<view class="u-demo">
|
||||||
|
<view class="u-demo-wrap">
|
||||||
|
<view class="u-demo-title">演示效果</view>
|
||||||
|
<view class="u-demo-area u-flex u-row-center">
|
||||||
|
[ BladeX ] 的官网为:{{domain}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-config-wrap">
|
||||||
|
<view class="u-config-title u-border-bottom">参数操作</view>
|
||||||
|
<view class="u-config-item">
|
||||||
|
<view class="u-item-title">按钮点击</view>
|
||||||
|
<u-button @click="modifyStorage">修改变量</u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
domain: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.domain = uni.getStorageSync('domain');
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
modifyStorage() {
|
||||||
|
uni.setStorageSync('domain', 'https://bladex.vip');
|
||||||
|
this.domain = uni.getStorageSync('domain');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }" title="Vuex 操作"
|
||||||
|
title-color="#fff">
|
||||||
|
</u-navbar>
|
||||||
|
<view class="u-demo">
|
||||||
|
<view class="u-demo-wrap">
|
||||||
|
<view class="u-demo-title">演示效果</view>
|
||||||
|
<view class="u-demo-area u-flex u-row-center">
|
||||||
|
<!-- vuex已做过封装,可以直接使用state内的变量 -->
|
||||||
|
版本号为:{{version}}
|
||||||
|
</view>
|
||||||
|
<view class="u-demo-area u-flex u-row-center">
|
||||||
|
[ BladeX ] 的作者为:{{userInfo.nickName}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-config-wrap">
|
||||||
|
<view class="u-config-title u-border-bottom">参数操作</view>
|
||||||
|
<view class="u-config-item">
|
||||||
|
<view class="u-item-title">按钮点击</view>
|
||||||
|
<u-button @click="modifyVuex">修改变量</u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
// vuex已做过封装,可以直接this.$u.vuex(key, value)修改,无需引入
|
||||||
|
modifyVuex() {
|
||||||
|
// version不在lifeData,每次刷新会丢失
|
||||||
|
this.$u.vuex('version', '1.0.1');
|
||||||
|
// userInfo在lifeData,刷新重启会保留
|
||||||
|
this.$u.vuex('userInfo.nickName', '翼');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,253 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 顶部标题栏 -->
|
||||||
|
<view class="header">
|
||||||
|
<text class="title">广西区直住房保障中心</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 预约功能区 -->
|
||||||
|
<view class="reserve-section">
|
||||||
|
<view class="reserve-card" @click="handleOnlineReserve">
|
||||||
|
<view class="icon online-icon"></view>
|
||||||
|
<text class="card-text">网上预约</text>
|
||||||
|
</view>
|
||||||
|
<view class="reserve-card" @click="handleMyReserve">
|
||||||
|
<view class="icon my-icon"></view>
|
||||||
|
<text class="card-text">我的预约</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 热门服务区 -->
|
||||||
|
<view class="service-section">
|
||||||
|
<text class="section-title">热门服务</text>
|
||||||
|
|
||||||
|
<view class="service-item" v-for="(item, index) in serviceList" :key="index"
|
||||||
|
@click="handleServiceClick(item)">
|
||||||
|
<view class="item-left">
|
||||||
|
<view class="dot"></view>
|
||||||
|
<text class="item-text">{{ item.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="arrow"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
deptList,
|
||||||
|
itemList
|
||||||
|
} from '@/api/reserve.js'
|
||||||
|
import {
|
||||||
|
dictionary
|
||||||
|
} from '@/api/system/dict.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 热门服务列表(和设计图完全一致)
|
||||||
|
serviceList: [],
|
||||||
|
statusList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.getItemList()
|
||||||
|
this.getDictionary()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDictionary() {
|
||||||
|
dictionary({
|
||||||
|
code: 'booking_status'
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.statusList = res.data
|
||||||
|
uni.setStorageSync('statusList', this.statusList);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 网上预约点击事件
|
||||||
|
handleOnlineReserve() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/reserve/index'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 我的预约点击事件
|
||||||
|
handleMyReserve() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/myReserve/index'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getItemList() {
|
||||||
|
let params = {
|
||||||
|
size: 5,
|
||||||
|
current: 1,
|
||||||
|
status: 1,
|
||||||
|
}
|
||||||
|
itemList(params).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.serviceList = res.data.records
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 服务项点击事件
|
||||||
|
handleServiceClick(item) {
|
||||||
|
const data = JSON.stringify(item)
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/reserve/notice?data=${encodeURIComponent(data)}`
|
||||||
|
})
|
||||||
|
// uni.navigateTo({
|
||||||
|
// url: `/pages/reserve/index?id=${item.id}`
|
||||||
|
// })
|
||||||
|
},
|
||||||
|
// // 获取部门列表
|
||||||
|
// getDeptList() {
|
||||||
|
// let params = {
|
||||||
|
// size: 10,
|
||||||
|
// current: 1
|
||||||
|
// }
|
||||||
|
// deptList(params).then(res => {
|
||||||
|
// if (res.code === 200) {
|
||||||
|
// this.serviceList = res.data.records.filter(item => item.parentId != 0)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局容器 */
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 顶部标题栏 */
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
height: 200rpx;
|
||||||
|
background: linear-gradient(to bottom, #e8f3ff 0%, #f5f5f5 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-image: url('/static/images/newImg/home_bg.png');
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(49, 134, 255, 1);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 预约功能区 */
|
||||||
|
.reserve-section {
|
||||||
|
display: flex;
|
||||||
|
padding: 0 30rpx 30rpx;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reserve-card {
|
||||||
|
flex: 1;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
padding: 40rpx 20rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online-icon {
|
||||||
|
background-image: url('@/static/images/newImg/online_icon.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-icon {
|
||||||
|
background-image: url('@/static/images/newImg/my_icon.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-text {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 热门服务区 */
|
||||||
|
.service-section {
|
||||||
|
padding: 0 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333333;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(to bottom, rgba(49, 134, 255, 1), rgba(21, 167, 255, 1));
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
font-size: 34rpx;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
border-right: 4rpx solid #165dff;
|
||||||
|
border-top: 4rpx solid #165dff;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
<template>
|
||||||
|
<!-- 空白loading页 -->
|
||||||
|
<view class="loading-container">
|
||||||
|
<view class="loading-text">正在登录中,请稍候...</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
login
|
||||||
|
} from '@/api/login.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
onLoad(options) {
|
||||||
|
// 页面加载 → 自动执行流程
|
||||||
|
this.getToken()
|
||||||
|
this.autoLogin(options)
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getToken() {
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.request({
|
||||||
|
url: '/epoint-web-cs/rest/oauth2/token',
|
||||||
|
method: 'POST',
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
client_id: '316f983b-2b93-4c57-b912-c00e05aceed2', // 你接口需要的参数名
|
||||||
|
client_secret: 'cd2cf239-1506-47bb-9b63-507b6b759a06',
|
||||||
|
grant_type: 'password',
|
||||||
|
platform: 'mobile',
|
||||||
|
username: '马贤宝',
|
||||||
|
password: 'Epoint@123',
|
||||||
|
// 其他需要的参数继续加
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
const data = res.data
|
||||||
|
console.log(data, 'data')
|
||||||
|
|
||||||
|
// 接口返回成功判断(根据接口标准结构)
|
||||||
|
if (data.status.code === 1) {
|
||||||
|
resolve(data.custom) // 返回用户信息:name, phone, idCard
|
||||||
|
} else {
|
||||||
|
reject(new Error(data.status.text || '获取用户信息失败'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 自动登录流程
|
||||||
|
*/
|
||||||
|
async autoLogin(options) {
|
||||||
|
try {
|
||||||
|
// 1. 从URL获取token
|
||||||
|
const token = options.token
|
||||||
|
if (!token) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '未获取到登录凭证',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 使用token 请求【获取用户信息接口】
|
||||||
|
const userInfo = await this.getUserInfo(token)
|
||||||
|
|
||||||
|
|
||||||
|
// 4. 执行你系统的登录逻辑(保存信息)
|
||||||
|
this.doLocalLogin(userInfo)
|
||||||
|
|
||||||
|
// 5. 登录成功 → 跳首页
|
||||||
|
// uni.switchTab({
|
||||||
|
// url: '/pages/home/home' // 你的首页路径
|
||||||
|
// })
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('登录失败:', err)
|
||||||
|
uni.showToast({
|
||||||
|
title: err.message || '登录失败,请重试',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 3000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求接口:获取用户信息(你给的正式接口)
|
||||||
|
* @param {string} token
|
||||||
|
*/
|
||||||
|
getUserInfo(token) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let url = '/epoint-web-cs/rest/wechatloginrest/getuserinfo'
|
||||||
|
|
||||||
|
// if (process.env.NODE_ENV === 'development') {
|
||||||
|
// // 开发环境接口地址
|
||||||
|
// url = 'epoint-web-cs/rest/wechatloginrest/getuserinfo'
|
||||||
|
// } else if (process.env.NODE_ENV === 'production') {
|
||||||
|
// // 正式环境接口地址
|
||||||
|
// url = 'epoint-web/rest/wechatloginrest/getuserinfo'
|
||||||
|
// }
|
||||||
|
|
||||||
|
uni.request({
|
||||||
|
url: url,
|
||||||
|
method: 'POST',
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
'authorization': 'Bearer ' + token // 按接口要求携带token
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
const data = res.data
|
||||||
|
|
||||||
|
// 接口返回成功判断(根据接口标准结构)
|
||||||
|
if (data.status.code === 1) {
|
||||||
|
resolve(data.custom) // 返回用户信息:name, phone, idCard
|
||||||
|
} else {
|
||||||
|
reject(new Error(data.status.text || '获取用户信息失败'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 你系统本地登录:缓存token + 用户信息
|
||||||
|
*/
|
||||||
|
doLocalLogin(userInfo) {
|
||||||
|
login({
|
||||||
|
// username: userInfo.idnumber,
|
||||||
|
username: userInfo.mobile,
|
||||||
|
|
||||||
|
grant_type: "third"
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.$u.func.login(data, '/pages/home/home')
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.$u.func.showToast({
|
||||||
|
title: '用户名或密码错误'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.loading-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="top">
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">账号</view>
|
||||||
|
<view class="input-box">
|
||||||
|
<input type="text" v-model="username" placeholder="请输入账号" class="ipt" placeholder-class="hold"
|
||||||
|
@blur="handleInputCheck" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">密码</view>
|
||||||
|
<view class="input-box">
|
||||||
|
<input type="password" v-model="password" placeholder="请输入密码" class="ipt"
|
||||||
|
placeholder-class="hold" @blur="handleInputCheck" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<button class="submit" @click="submit" :disabled="disabled">登录</button>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<!-- -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import sm2 from '@/utils/sm2.js'
|
||||||
|
import {
|
||||||
|
publicKey
|
||||||
|
} from '@/common/setting'
|
||||||
|
export default {
|
||||||
|
onLoad(option) {
|
||||||
|
const {
|
||||||
|
redirect
|
||||||
|
} = option
|
||||||
|
if (redirect) this.redirect = redirect
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tenantId: '000000',
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
disabled: false,
|
||||||
|
redirect: '/pages/home/home'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit() {
|
||||||
|
this.$u.api
|
||||||
|
.token(this.tenantId, this.username, sm2.doEncrypt(this.password, publicKey, 0))
|
||||||
|
.then(data => {
|
||||||
|
this.$u.func.login(data, this.redirect)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
this.$u.func.showToast({
|
||||||
|
title: '用户名或密码错误'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleInputCheck() {
|
||||||
|
this.disabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.set-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 41rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 35rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
height: 90vh;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.top {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: block;
|
||||||
|
width: 281rpx;
|
||||||
|
height: auto;
|
||||||
|
margin: 0 auto 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 85rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-top: 36rpx;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3e4a59;
|
||||||
|
line-height: 30rpx;
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box {
|
||||||
|
padding: 30rpx 0;
|
||||||
|
border-bottom: 2rpx solid #f6f6f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.code {
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #0d0d0d;
|
||||||
|
line-height: 30rpx;
|
||||||
|
|
||||||
|
text {
|
||||||
|
// color: #14b9c8;
|
||||||
|
color: #5f88ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ipt {
|
||||||
|
flex: 1;
|
||||||
|
// height: 24rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hold {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3e4a59;
|
||||||
|
line-height: 30px;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree {
|
||||||
|
margin: 27rpx 95rpx 0;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #cacaca;
|
||||||
|
line-height: 34rpx;
|
||||||
|
|
||||||
|
.a {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
margin: 60rpx 90rpx 0;
|
||||||
|
border: none;
|
||||||
|
width: 572rpx;
|
||||||
|
height: 86rpx;
|
||||||
|
line-height: 86rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 15rpx;
|
||||||
|
background-color: #5f88ff;
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled='true'] {
|
||||||
|
background: #e4e4e4;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #cacaca;
|
||||||
|
line-height: 34rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
// color: #14b9c8;
|
||||||
|
color: #5f88ff;
|
||||||
|
line-height: 34rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #9f9f9f;
|
||||||
|
line-height: 34rpx;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 1px;
|
||||||
|
background: #d8d8d8;
|
||||||
|
opacity: 0.86;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 1px;
|
||||||
|
background: #d8d8d8;
|
||||||
|
opacity: 0.86;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-arr {
|
||||||
|
margin-top: 50rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 73rpx;
|
||||||
|
height: 73rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,291 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="false" back-icon-name="arrow-leftward" title="登录"
|
||||||
|
:background="{ background: '#fff' }" title-color="#000000">
|
||||||
|
<view class="" slot="right">
|
||||||
|
<image src="/static/images/user/c8.png" class="set-icon" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</u-navbar>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="top">
|
||||||
|
<image src="/static/images/logo.png" class="logo" mode="widthFix"></image>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">手机号</view>
|
||||||
|
<view class="input-box">
|
||||||
|
<input type="number" v-model="phone" placeholder="请输入手机号码" class="ipt" placeholder-class="hold"
|
||||||
|
@blur="handleInputCheck" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">短信验证码</view>
|
||||||
|
<view class="input-box">
|
||||||
|
<input type="number" v-model="code" placeholder="请输入验证码" class="ipt" placeholder-class="hold"
|
||||||
|
@blur="handleInputCheck" />
|
||||||
|
<view class="code" @click="sendCode" v-if="count === 60">获取验证码</view>
|
||||||
|
<view class="code" v-else><text>{{ count }}</text>秒重新获取</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- <view class="agree">
|
||||||
|
登录即代表同意
|
||||||
|
<text class="a">《用户协议》</text>
|
||||||
|
和
|
||||||
|
<text class="a">《隐私政策》</text>
|
||||||
|
</view> -->
|
||||||
|
<button class="submit" @click="submit" :disabled="disabled">登录</button>
|
||||||
|
<view class="tip">未注册用户验证后将自动注册并登录</view>
|
||||||
|
<navigator url="/pages/login/login-account" hover-class="none" class="change">密码登录 ></navigator>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 社交账号登录 -->
|
||||||
|
<view class="bottom">
|
||||||
|
<view class="tag">社交账号登录</view>
|
||||||
|
<view class="chat-arr">
|
||||||
|
<image src="/static/images/wx.png" class="icon" mode=""></image>
|
||||||
|
<image src="/static/images/qq.png" class="icon" mode=""></image>
|
||||||
|
<image src="/static/images/wb.png" class="icon" mode=""></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
phone: '',
|
||||||
|
code: '',
|
||||||
|
disabled: true,
|
||||||
|
count: 60,
|
||||||
|
timer: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
submit() {
|
||||||
|
this.$u.func.showToast({
|
||||||
|
title: '新版本即将到来',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleInputCheck() {
|
||||||
|
if (!this.phone && !/^1\d{10}$/.test(this.phone)) {
|
||||||
|
this.disabled = true
|
||||||
|
return uni.showToast({
|
||||||
|
title: '请输入正确的手机号',
|
||||||
|
duration: 2000,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!this.code) {
|
||||||
|
this.disabled = true
|
||||||
|
return uni.showToast({
|
||||||
|
title: '请输入验证码',
|
||||||
|
duration: 2000,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.disabled = false
|
||||||
|
},
|
||||||
|
async sendCode() {
|
||||||
|
this.count = this.count - 1;
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
if (this.count == 0) {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.count = 60;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.count = this.count - 1;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.set-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 41rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 35rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
height: 90vh;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.top {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: block;
|
||||||
|
width: 281rpx;
|
||||||
|
height: auto;
|
||||||
|
margin: 0 auto 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 85rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-top: 36rpx;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3e4a59;
|
||||||
|
line-height: 30rpx;
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-box {
|
||||||
|
padding: 30rpx 0;
|
||||||
|
border-bottom: 2rpx solid #f0f2f5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.code {
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #0d0d0d;
|
||||||
|
line-height: 30rpx;
|
||||||
|
|
||||||
|
text {
|
||||||
|
// color: #14b9c8;
|
||||||
|
color: #5f88ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ipt {
|
||||||
|
flex: 1;
|
||||||
|
// height: 24rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hold {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #3e4a59;
|
||||||
|
line-height: 30px;
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.agree {
|
||||||
|
margin: 27rpx 95rpx 0;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #cacaca;
|
||||||
|
line-height: 34rpx;
|
||||||
|
|
||||||
|
.a {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
margin: 60rpx 90rpx 0;
|
||||||
|
border: none;
|
||||||
|
width: 572rpx;
|
||||||
|
height: 86rpx;
|
||||||
|
line-height: 86rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 15rpx;
|
||||||
|
background-color: #5f88ff;
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled='true'] {
|
||||||
|
background: #e4e4e4;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #cacaca;
|
||||||
|
line-height: 34rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #69b0ff;
|
||||||
|
line-height: 34rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-family: Adobe Heiti Std;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #9f9f9f;
|
||||||
|
line-height: 34rpx;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 1px;
|
||||||
|
background: #d8d8d8;
|
||||||
|
opacity: 0.86;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 1px;
|
||||||
|
background: #d8d8d8;
|
||||||
|
opacity: 0.86;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-arr {
|
||||||
|
margin-top: 50rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 73rpx;
|
||||||
|
height: 73rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,377 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@search="onSearch"
|
||||||
|
@child="onChildren"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<u-form-item label="机构名称" prop="deptName" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.deptName" :disabled="readonly" placeholder="机构名称" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="机构全称" prop="fullName" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.fullName" :disabled="readonly" placeholder="机构全称" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="上级机构" prop="parentId" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-if="!isAddChild"
|
||||||
|
v-model="formLabel.parentName"
|
||||||
|
placeholder="机构全称"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) $refs.treePicker._show()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<u-input v-else v-model="formLabel.parentName" placeholder="机构全称" disabled />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="机构类型" prop="deptCategory" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-model="formLabel.category"
|
||||||
|
placeholder="机构类型"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) categoryShow = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="排序" prop="sort" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.sort" :disabled="readonly" type="number" placeholder="排序" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="描述" :label-width="option.labelWidth || 160" prop="remark">
|
||||||
|
<u-input v-model="form.remark" :disabled="readonly" type="textarea" :maxlength="-1" :height="35" placeholder="描述" />
|
||||||
|
</u-form-item>
|
||||||
|
</template>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
<u-select
|
||||||
|
v-model="categoryShow"
|
||||||
|
:list="categoryList"
|
||||||
|
value-name="dictKey"
|
||||||
|
label-name="dictValue"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
></u-select>
|
||||||
|
<!-- 上级机构tree -->
|
||||||
|
<rider-tree
|
||||||
|
ref="treePicker"
|
||||||
|
:range="deptTreeList"
|
||||||
|
idKey="id"
|
||||||
|
nameKey="title"
|
||||||
|
:multiple="false"
|
||||||
|
:cascade="false"
|
||||||
|
:foldAll="false"
|
||||||
|
confirmColor="#4E7FF9"
|
||||||
|
cancelColor="#757575"
|
||||||
|
title="上级机构"
|
||||||
|
titleColor="#757575"
|
||||||
|
@cancel="$refs.treePicker._hide()"
|
||||||
|
@confirm="onTreeConfirm"
|
||||||
|
></rider-tree>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import riderTree from '@/components/rider-crud/components/tree-picker'
|
||||||
|
import { getList, add, update, remove, deptTree } from '@/api/system/dept.js'
|
||||||
|
import { tenantSelect } from '@/api/system/tenant.js'
|
||||||
|
import { dictionary } from '@/api/system/dict.js'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd, riderTree },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
checkedSwitch: false,
|
||||||
|
form: {},
|
||||||
|
formLabel: {},
|
||||||
|
list: [],
|
||||||
|
params: {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
parentId: 0
|
||||||
|
},
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
option: {
|
||||||
|
navTitle: '部门管理', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '机构名称',
|
||||||
|
prop: 'deptName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属租户',
|
||||||
|
prop: 'tenantName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '机构全称',
|
||||||
|
prop: 'fullName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '机构类型',
|
||||||
|
prop: 'deptCategoryName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '排序',
|
||||||
|
prop: 'sort'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '描述',
|
||||||
|
prop: 'remark'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '新增子项',
|
||||||
|
icon: 'plus',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
deptCategory: [{ required: true, message: '请选择机构类型', trigger: 'change', type: 'number' }],
|
||||||
|
deptName: [{ required: true, message: '请输入机构名称', trigger: 'blur' }],
|
||||||
|
fullName: [{ required: true, message: '请输入机构全称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入排序', trigger: 'blur', type: 'number' }]
|
||||||
|
},
|
||||||
|
categoryShow: false,
|
||||||
|
categoryList: [],
|
||||||
|
tenantList: [],
|
||||||
|
deptTreeList: [],
|
||||||
|
isAddChild: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onReady() {
|
||||||
|
this.getList(true)
|
||||||
|
this.getTenant().then(() => {
|
||||||
|
this.getList(true)
|
||||||
|
})
|
||||||
|
this.getCategoryList()
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
getList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const records = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) this.list = records
|
||||||
|
else this.list = this.list.concat(records)
|
||||||
|
if (this.list && this.list.length > 0) {
|
||||||
|
this.list.map(e => {
|
||||||
|
e.tenantName = getDicLabel(e.tenantId, this.tenantList, { label: 'tenantName', value: 'tenantId' })
|
||||||
|
e.children = []
|
||||||
|
})
|
||||||
|
this.$refs.crud.setLazyLoad((item, index, cb) => {
|
||||||
|
getList({ parentId: item.id }).then(res => {
|
||||||
|
res.data.map(e => {
|
||||||
|
e.tenantName = getDicLabel(e.tenantId, this.tenantList, { label: 'tenantName', value: 'tenantId' })
|
||||||
|
})
|
||||||
|
cb(res.data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.params.current++
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取类型
|
||||||
|
getCategoryList() {
|
||||||
|
dictionary({ code: 'org_category' }).then(res => {
|
||||||
|
this.categoryList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 租户类型
|
||||||
|
getTenant() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
deptTree().then(res => {
|
||||||
|
this.deptTreeList = res.data
|
||||||
|
})
|
||||||
|
tenantSelect().then(res => {
|
||||||
|
this.tenantList = res.data
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 类型回调
|
||||||
|
onConfirm(e) {
|
||||||
|
this.$set(this.formLabel, 'category', e[0].label)
|
||||||
|
this.$set(this.form, 'deptCategory', Number(e[0].value))
|
||||||
|
},
|
||||||
|
//上级机构选择回调
|
||||||
|
onTreeConfirm(e) {
|
||||||
|
this.$set(this.form, 'parentId', e[0].id)
|
||||||
|
this.$set(this.formLabel, 'parentName', e[0].name)
|
||||||
|
},
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
deptName: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
this.form = {}
|
||||||
|
this.formLabel = {}
|
||||||
|
this.isAddChild = false
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
this.isAddChild = false
|
||||||
|
this.formLabel = {
|
||||||
|
category: getDicLabel(data.deptCategory, this.categoryList),
|
||||||
|
parentName: getDicLabel(data.parentId, this.deptTreeList, { label: 'title', value: 'id' })
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '新增子项':
|
||||||
|
this.isAddChild = true
|
||||||
|
this.form = {}
|
||||||
|
this.formLabel = {
|
||||||
|
parentName: getDicLabel(data.id, this.deptTreeList, { label: 'title', value: 'id' })
|
||||||
|
}
|
||||||
|
this.$set(this.form, 'parentId', data.id)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (['删除', '编辑', '新增子项'].includes(name)) this.$refs['crud'].hideChildren()
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增' || action == '新增子项') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-right {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-right: 24rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,489 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@search="onSearch"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<u-form-item label="字典编号" prop="code" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.code" :disabled="readonly" placeholder="字典编号" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典名称" prop="dictValue" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.dictValue" :disabled="readonly" placeholder="字典名称" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典排序" prop="sort" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.sort" :disabled="readonly" type="number" placeholder="字典排序" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="封存" prop="isSealed" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-radio-group v-model="form.isSealed" :disabled="readonly">
|
||||||
|
<u-radio shape="circle" :name="1" active-color="#4E7FF9">是</u-radio>
|
||||||
|
<u-radio shape="circle" :name="0" active-color="#4E7FF9">否</u-radio>
|
||||||
|
</u-radio-group>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典备注" :label-width="option.labelWidth || 160" prop="remark">
|
||||||
|
<u-input
|
||||||
|
v-model="form.remark"
|
||||||
|
:disabled="readonly"
|
||||||
|
type="textarea"
|
||||||
|
:maxlength="-1"
|
||||||
|
:height="35"
|
||||||
|
placeholder="字典备注"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
</template>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
<!-- 字典配置 -->
|
||||||
|
<u-popup v-model="configShow" mode="bottom" height="100vh" @close="onConfigClose" :mask-close-able="false">
|
||||||
|
<scroll-view scroll-y="true" style="height: 100vh; background: #f5f5f5">
|
||||||
|
<rider-curd
|
||||||
|
ref="childCrud"
|
||||||
|
v-model="childForm"
|
||||||
|
:navBack="onConfigClose"
|
||||||
|
@search="onChildSearch"
|
||||||
|
:option="{ ...configOption, navTitle: `${configName} - 字典配置` }"
|
||||||
|
:data="childList"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<u-form-item label="字典编号" prop="code" :label-width="configOption.labelWidth || 160" required>
|
||||||
|
<u-input v-model="childForm.code" disabled placeholder="字典编号" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典名称" prop="dictValue" :label-width="configOption.labelWidth || 160" required>
|
||||||
|
<u-input v-model="childForm.dictValue" :disabled="readonly" placeholder="字典名称" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="上级字典" :label-width="configOption.labelWidth || 160">
|
||||||
|
<u-input v-model="parentData.dictValue" disabled placeholder="上级字典" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典键值" prop="dictKey" :label-width="configOption.labelWidth || 160" required>
|
||||||
|
<u-input v-model="childForm.dictKey" :disabled="readonly" placeholder="字典键值" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典排序" prop="sort" :label-width="configOption.labelWidth || 160" required>
|
||||||
|
<u-input v-model="childForm.sort" :disabled="readonly" type="number" placeholder="字典排序" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="封存" prop="isSealed" :label-width="configOption.labelWidth || 160" required>
|
||||||
|
<u-radio-group v-model="childForm.isSealed" :disabled="readonly">
|
||||||
|
<u-radio shape="circle" :name="1" active-color="#4E7FF9">是</u-radio>
|
||||||
|
<u-radio shape="circle" :name="0" active-color="#4E7FF9">否</u-radio>
|
||||||
|
</u-radio-group>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="字典备注" prop="remark" :label-width="configOption.labelWidth || 160">
|
||||||
|
<u-input
|
||||||
|
v-model="childForm.remark"
|
||||||
|
:disabled="readonly"
|
||||||
|
type="textarea"
|
||||||
|
:maxlength="-1"
|
||||||
|
:height="35"
|
||||||
|
placeholder="字典备注"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
</template>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="childLoadStatus" @loadmore="getChild()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</scroll-view>
|
||||||
|
</u-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import { parentList, add, update, remove, dictionary, child, dictTree } from '@/api/system/dict.js'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
configShow: false, //字典管理弹窗
|
||||||
|
form: {
|
||||||
|
isSealed: 0
|
||||||
|
},
|
||||||
|
list: [],
|
||||||
|
params: {
|
||||||
|
current: 1,
|
||||||
|
size: 10
|
||||||
|
},
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
parentData: {}, // 上级数据信息
|
||||||
|
childList: [],
|
||||||
|
childForm: {
|
||||||
|
isSealed: 0
|
||||||
|
},
|
||||||
|
childParams: {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
parentId: null
|
||||||
|
},
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
childLoadStatus: 'loadmore', // 列表加载状态
|
||||||
|
option: {
|
||||||
|
navTitle: '字典管理', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '字典编号',
|
||||||
|
prop: 'code'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '字典名称',
|
||||||
|
prop: 'dictValue'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: '字典排序',
|
||||||
|
prop: 'sort'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '封存',
|
||||||
|
prop: 'sealedName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '字典备注',
|
||||||
|
prop: 'remark'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '设置',
|
||||||
|
icon: 'setting',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
configName: '',
|
||||||
|
configOption: {
|
||||||
|
navBackIcon: 'close', //导航栏左上角icon
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '字典编号',
|
||||||
|
prop: 'code'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '字典名称',
|
||||||
|
prop: 'dictValue'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '字典键值',
|
||||||
|
prop: 'dictKey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '字典排序',
|
||||||
|
prop: 'sort'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '封存',
|
||||||
|
prop: 'sealedName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '字典备注',
|
||||||
|
prop: 'remark'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '新增子项',
|
||||||
|
icon: 'plus',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
code: [{ required: true, message: '请输入字典编号', trigger: 'blur' }],
|
||||||
|
dictValue: [{ required: true, message: '请输入字典名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入字典排序', trigger: 'blur', type: 'number' }],
|
||||||
|
isSealed: [{ required: true, message: '请选择是否封存', trigger: 'blur', type: 'number' }],
|
||||||
|
dictKey: [{ required: true, message: '请输入字典键值', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onReady() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
this.getChild(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
|
||||||
|
if (this.childLoadStatus == 'nomore') return
|
||||||
|
this.getChild()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
parentList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const { records } = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.list = records
|
||||||
|
} else {
|
||||||
|
this.list = this.list.concat(records)
|
||||||
|
}
|
||||||
|
if (this.list && this.list.length > 0) {
|
||||||
|
this.list.map(e => {
|
||||||
|
e.sealedName = e.isSealed ? '是' : '否'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.params.current++
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取子类列表
|
||||||
|
getChild(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.childParams.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.childParams
|
||||||
|
child(this.childParams)
|
||||||
|
.then(res => {
|
||||||
|
const records = res.data
|
||||||
|
if (records.length < size) this.childLoadStatus = 'nomore'
|
||||||
|
else this.childLoadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.childList = records
|
||||||
|
} else {
|
||||||
|
this.childList = this.childList.concat(records)
|
||||||
|
}
|
||||||
|
if (this.childList && this.childList.length > 0) {
|
||||||
|
this.childList.map(e => {
|
||||||
|
e.sealedName = e.isSealed ? '是' : '否'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.childParams.current++
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
if (this.parentData.code) {
|
||||||
|
this.$set(this.childForm, 'code', this.parentData.code)
|
||||||
|
this.$set(this.childForm, 'parentId', this.parentData.id)
|
||||||
|
this.$set(this.childParams, 'parentId', this.parentData.id)
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
if (data.id) done()
|
||||||
|
break
|
||||||
|
case '设置':
|
||||||
|
this.childForm = {}
|
||||||
|
this.parentData = data
|
||||||
|
this.configName = data.dictValue
|
||||||
|
this.$set(this.childParams, 'parentId', data.id)
|
||||||
|
this.getChild(true)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.configShow = true
|
||||||
|
}, 100)
|
||||||
|
break
|
||||||
|
case '新增子项':
|
||||||
|
this.childForm = {}
|
||||||
|
this.parentData = data
|
||||||
|
this.$set(this.childForm, 'code', data.code)
|
||||||
|
this.$set(this.childForm, 'parentId', data.id)
|
||||||
|
this.$set(this.childParams, 'parentId', data.id)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (['删除', '编辑', '新增子项'].includes(name)) {
|
||||||
|
this.$refs['crud'].hideChildren()
|
||||||
|
this.$refs['childCrud'].hideChildren()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增' || action == '新增子项') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//字典配置关闭
|
||||||
|
onConfigClose() {
|
||||||
|
this.configShow = false
|
||||||
|
this.childParams = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
parentId: null
|
||||||
|
}
|
||||||
|
this.parentData = {}
|
||||||
|
this.form = { isSealed: 0 }
|
||||||
|
this.childForm = { isSealed: 0 }
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getChild(true)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
dictValue: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 子级搜索
|
||||||
|
onChildSearch(val) {
|
||||||
|
this.childForm = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
dictValue: val
|
||||||
|
}
|
||||||
|
this.getChild(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-right {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-right: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-title {
|
||||||
|
padding: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 20rpx solid #f5f5f5;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(45deg, #4e7ff9 0%, #59a5fb 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar
|
||||||
|
:is-fixed="false"
|
||||||
|
:border-bottom="false"
|
||||||
|
:is-back="false"
|
||||||
|
title="管理"
|
||||||
|
:background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }"
|
||||||
|
title-color="#fff"
|
||||||
|
>
|
||||||
|
<image slot="right" src="/static/images/home/message.png" class="message-icon" mode="widthFix"></image>
|
||||||
|
</u-navbar>
|
||||||
|
|
||||||
|
<view class="tab">
|
||||||
|
<u-tabs
|
||||||
|
:list="list"
|
||||||
|
:is-scroll="false"
|
||||||
|
:current="current"
|
||||||
|
active-color="#5f88ff"
|
||||||
|
inactive-color="#595959"
|
||||||
|
height="100"
|
||||||
|
@change="change"
|
||||||
|
></u-tabs>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<swiper id="swiperBox" :style="{ height: swiperHeight + 'px' }" :current="current" @change="tabsChange">
|
||||||
|
|
||||||
|
<swiper-item class="swiper-item" key="0">
|
||||||
|
<scroll-view scroll-y style="width: 100%;height: 100%;" @scrolltolower="onreachBottom">
|
||||||
|
<view class="content">
|
||||||
|
<u-grid :col="3">
|
||||||
|
<u-grid-item v-for="(_item, _index) in deskList" :key="_index">
|
||||||
|
<navigator :url="_item.path" hover-class="none" class="gitem">
|
||||||
|
<image :src="require(`@/static/images/manage/${_item.type}.png`)" class="img" mode="widthFix"></image>
|
||||||
|
<view class="name">{{ _item.name }}</view>
|
||||||
|
</navigator>
|
||||||
|
</u-grid-item>
|
||||||
|
</u-grid>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</swiper-item>
|
||||||
|
|
||||||
|
<swiper-item class="swiper-item" key="1">
|
||||||
|
<scroll-view scroll-y style="width: 100%;height: 100%;" @scrolltolower="onreachBottom">
|
||||||
|
<view class="content">
|
||||||
|
<u-grid :col="3">
|
||||||
|
<u-grid-item v-for="(_item, _index) in systemList" :key="_index">
|
||||||
|
<navigator :url="_item.path" hover-class="none" class="gitem">
|
||||||
|
<image :src="require(`@/static/images/manage/${_item.type}.png`)" class="img" mode="widthFix"></image>
|
||||||
|
<view class="name">{{ _item.name }}</view>
|
||||||
|
</navigator>
|
||||||
|
</u-grid-item>
|
||||||
|
</u-grid>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
current: 0,
|
||||||
|
swiperHeight: 0,
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
name: '工作台'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '系统'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
deskList: [
|
||||||
|
{
|
||||||
|
name: '公告',
|
||||||
|
type: 'notice',
|
||||||
|
path: '/pages/manage/notice'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
systemList: [
|
||||||
|
{
|
||||||
|
name: '角色',
|
||||||
|
type: 'role',
|
||||||
|
path: '/pages/manage/role'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '部门',
|
||||||
|
type: 'dept',
|
||||||
|
path: '/pages/manage/dept'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '字典',
|
||||||
|
type: 'dict',
|
||||||
|
path: '/pages/manage/dict'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '岗位',
|
||||||
|
type: 'post',
|
||||||
|
path: '/pages/manage/post'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
let that = this
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success(e) {
|
||||||
|
console.log(e)
|
||||||
|
let { windowWidth, windowHeight, safeArea } = e
|
||||||
|
const query = uni.createSelectorQuery().in(that)
|
||||||
|
query
|
||||||
|
.select('#swiperBox')
|
||||||
|
.boundingClientRect(data => {
|
||||||
|
that.swiperHeight = safeArea.bottom - data.top
|
||||||
|
})
|
||||||
|
.exec()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
tabsChange(e) {
|
||||||
|
this.current = e.detail.current
|
||||||
|
},
|
||||||
|
change(index) {
|
||||||
|
this.current = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.swiper-box {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-icon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 27rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gitem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.img {
|
||||||
|
width: 54rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #030305;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,326 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@search="onSearch"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<view slot="form">
|
||||||
|
<u-form-item label="通知标题" prop="title" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.title" :disabled="readonly" placeholder="通知标题" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="通知类型" prop="category" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-model="formLabel.category"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="通知类型"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) categoryShow = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="通知日期" prop="releaseTime" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-model="form.releaseTime"
|
||||||
|
:disabled="readonly"
|
||||||
|
placeholder="通知日期"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) timeShow = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="通知内容" :label-width="option.labelWidth || 160" :border-bottom="false">
|
||||||
|
<template #right v-if="!readonly">
|
||||||
|
<u-button
|
||||||
|
@click="onRichEdit(form.content)"
|
||||||
|
ripple
|
||||||
|
:custom-style="{ background: '#FFF6E9', color: '#FAA646' }"
|
||||||
|
size="mini"
|
||||||
|
>
|
||||||
|
去编辑
|
||||||
|
</u-button>
|
||||||
|
</template>
|
||||||
|
</u-form-item>
|
||||||
|
<mp-html :content="form.content"></mp-html>
|
||||||
|
</view>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
<!-- 通知类型 -->
|
||||||
|
<u-select
|
||||||
|
v-model="categoryShow"
|
||||||
|
:list="categoryList"
|
||||||
|
value-name="dictKey"
|
||||||
|
label-name="dictValue"
|
||||||
|
@confirm="e => onConfirm(e, 'category')"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
></u-select>
|
||||||
|
<!-- 通知日期 -->
|
||||||
|
<u-picker
|
||||||
|
mode="time"
|
||||||
|
v-model="timeShow"
|
||||||
|
:params="timeParams"
|
||||||
|
start-year="2000"
|
||||||
|
end-year="2050"
|
||||||
|
@confirm="e => onConfirm(e, 'releaseTime')"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
></u-picker>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import mpHtml from '@/components/rider-crud/components/mp-html/mp-html'
|
||||||
|
import { getList, add, update, remove } from '@/api/notice.js'
|
||||||
|
import { dictionary } from '@/api/system/dict.js'
|
||||||
|
import { logo } from '../../common/setting'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd, mpHtml },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
checkedSwitch: false, // 默认打开管理
|
||||||
|
form: { content: '' }, // 表单
|
||||||
|
formLabel: {}, // 表单label
|
||||||
|
list: [], // 列表数据
|
||||||
|
params: {
|
||||||
|
// 分页
|
||||||
|
current: 1,
|
||||||
|
size: 10
|
||||||
|
},
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
option: {
|
||||||
|
// 组件选项
|
||||||
|
navTitle: '通知公告', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '通知标题',
|
||||||
|
prop: 'title'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通知类型',
|
||||||
|
prop: 'categoryName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '通知日期',
|
||||||
|
prop: 'releaseTime'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
// 左滑操作按钮
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// 表单校验规则
|
||||||
|
title: [{ required: true, message: '请输入通知标题', trigger: 'blur' }],
|
||||||
|
category: [{ required: true, message: '请选择通知类型', trigger: 'change', type: 'number' }],
|
||||||
|
releaseTime: [{ required: true, message: '请选择通知日期', trigger: 'change' }]
|
||||||
|
},
|
||||||
|
timeShow: false,
|
||||||
|
timeParams: {
|
||||||
|
year: true,
|
||||||
|
month: true,
|
||||||
|
day: true,
|
||||||
|
hour: true,
|
||||||
|
minute: true,
|
||||||
|
second: true
|
||||||
|
},
|
||||||
|
categoryShow: false,
|
||||||
|
categoryList: [] //类型
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
let that = this
|
||||||
|
uni.$on('richBack', function(data) {
|
||||||
|
that.$set(that.form, 'content', data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.getList(true)
|
||||||
|
this.getCategoryList()
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
getList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const { records, current } = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.list = records
|
||||||
|
} else {
|
||||||
|
this.list = this.list.concat(records)
|
||||||
|
}
|
||||||
|
this.params.current++
|
||||||
|
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 通知类型
|
||||||
|
getCategoryList() {
|
||||||
|
dictionary({ code: 'notice' }).then(res => {
|
||||||
|
this.categoryList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 类型回调
|
||||||
|
onConfirm(e, type) {
|
||||||
|
if (type == 'category') {
|
||||||
|
this.formLabel[type] = e[0].label
|
||||||
|
this.form.category = Number(e[0].value)
|
||||||
|
} else {
|
||||||
|
this.$set(this.form, 'releaseTime', e.year + '-' + e.month + '-' + e.day + ' ' + e.hour + ':' + e.minute + ':' + e.second)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 编辑富文本
|
||||||
|
onRichEdit(e) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/rich/index?data=${e}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
title: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
this.formLabel = {}
|
||||||
|
this.form = { content: '' }
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
this.formLabel.category = getDicLabel(data.category, this.categoryList)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = {}
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = {}
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,311 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@search="onSearch"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<u-form-item label="岗位类型" prop="category" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input
|
||||||
|
v-model="formLabel.category"
|
||||||
|
placeholder="角色名称"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) categoryShow = true
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="岗位编号" prop="postCode" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.postCode" :disabled="readonly" placeholder="岗位编号" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="岗位名称" prop="postName" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.postName" :disabled="readonly" placeholder="岗位名称" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="岗位排序" prop="sort" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.sort" :disabled="readonly" type="number" placeholder="岗位排序" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="岗位描述" prop="remark" :label-width="option.labelWidth || 160">
|
||||||
|
<u-input
|
||||||
|
v-model="form.remark"
|
||||||
|
:disabled="readonly"
|
||||||
|
type="textarea"
|
||||||
|
:maxlength="-1"
|
||||||
|
:height="35"
|
||||||
|
placeholder="岗位描述"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
</template>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
<u-select
|
||||||
|
v-model="categoryShow"
|
||||||
|
:list="categoryList"
|
||||||
|
value-name="dictKey"
|
||||||
|
label-name="dictValue"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
></u-select>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import { getList, add, update, remove } from '@/api/system/post.js'
|
||||||
|
import { tenantSelect } from '@/api/system/tenant.js'
|
||||||
|
import { dictionary } from '@/api/system/dict.js'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
checkedSwitch: false,
|
||||||
|
form: {},
|
||||||
|
formLabel: {},
|
||||||
|
list: [],
|
||||||
|
params: {
|
||||||
|
current: 1,
|
||||||
|
size: 10
|
||||||
|
},
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
option: {
|
||||||
|
navTitle: '岗位管理', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '岗位名称',
|
||||||
|
prop: 'postName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '岗位编号',
|
||||||
|
prop: 'postCode'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属租户',
|
||||||
|
prop: 'tenantName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '岗位类型',
|
||||||
|
prop: 'categoryName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '岗位排序',
|
||||||
|
prop: 'sort'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '岗位描述',
|
||||||
|
prop: 'remark'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
category: [{ required: true, message: '请选择岗位类型', trigger: 'change', type: 'number' }],
|
||||||
|
postCode: [{ required: true, message: '请输入岗位编号', trigger: 'blur' }],
|
||||||
|
postName: [{ required: true, message: '请输入岗位名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入岗位排序', trigger: 'blur', type: 'number' }]
|
||||||
|
},
|
||||||
|
categoryShow: false,
|
||||||
|
categoryList: [],
|
||||||
|
category: '',
|
||||||
|
tenantList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onReady() {
|
||||||
|
this.getTenant().then(() => {
|
||||||
|
this.getList(true)
|
||||||
|
})
|
||||||
|
this.getCategoryList()
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
getList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const { records, current } = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.list = records
|
||||||
|
} else {
|
||||||
|
this.list = this.list.concat(records)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.list && this.list.length > 0) {
|
||||||
|
this.list.map(e => {
|
||||||
|
e.tenantName = getDicLabel(e.tenantId, this.tenantList, { label: 'tenantName', value: 'tenantId' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.params.current++
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取类型
|
||||||
|
getCategoryList() {
|
||||||
|
dictionary({ code: 'post_category' }).then(res => {
|
||||||
|
this.categoryList = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 租户类型
|
||||||
|
getTenant() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
tenantSelect().then(res => {
|
||||||
|
this.tenantList = res.data
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 类型回调
|
||||||
|
onConfirm(e) {
|
||||||
|
this.$set(this.form, 'category', Number(e[0].value))
|
||||||
|
this.$set(this.formLabel, 'category', e[0].label)
|
||||||
|
},
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
postName: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
console.log(name, index)
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
this.formLabel.category = getDicLabel(data.category, this.categoryList)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = {}
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
this.formLabel = {}
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-right {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-right: 24rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,372 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="safe-area-inset-bottom">
|
||||||
|
<rider-curd
|
||||||
|
v-model="form"
|
||||||
|
:option="option"
|
||||||
|
:data="list"
|
||||||
|
:rules="rules"
|
||||||
|
:readonly.sync="readonly"
|
||||||
|
@search="onSearch"
|
||||||
|
@action-click="onActionClick"
|
||||||
|
@submit="onSubmit"
|
||||||
|
@del="onRemove"
|
||||||
|
ref="crud"
|
||||||
|
>
|
||||||
|
<template #form>
|
||||||
|
<u-form-item label="角色名称" prop="roleName" :label-width="option.labelWidth || 160" required>
|
||||||
|
<u-input v-model="form.roleName" :disabled="readonly" placeholder="角色名称" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="上级角色" prop="parentId" :label-width="option.labelWidth || 160">
|
||||||
|
<u-input
|
||||||
|
v-model="formLabel.parentName"
|
||||||
|
placeholder="上级角色"
|
||||||
|
type="select"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
if (!readonly) $refs.treePicker._show()
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="角色别名" prop="roleAlias" required :label-width="option.labelWidth || 160">
|
||||||
|
<u-input v-model="form.roleAlias" :disabled="readonly" placeholder="角色别名" />
|
||||||
|
</u-form-item>
|
||||||
|
<u-form-item label="角色排序" prop="sort" required :label-width="option.labelWidth || 160">
|
||||||
|
<u-input v-model="form.sort" :disabled="readonly" type="number" placeholder="角色排序" />
|
||||||
|
</u-form-item>
|
||||||
|
</template>
|
||||||
|
<template #loadmore>
|
||||||
|
<u-loadmore :status="loadStatus" @loadmore="getList()" />
|
||||||
|
</template>
|
||||||
|
</rider-curd>
|
||||||
|
</view>
|
||||||
|
<!-- 上级角色tree -->
|
||||||
|
<rider-tree
|
||||||
|
ref="treePicker"
|
||||||
|
:range="roleTreeList"
|
||||||
|
@cancel="$refs.treePicker._hide()"
|
||||||
|
@confirm="onTreeConfirm"
|
||||||
|
idKey="id"
|
||||||
|
nameKey="title"
|
||||||
|
:multiple="false"
|
||||||
|
:cascade="false"
|
||||||
|
:foldAll="false"
|
||||||
|
confirmColor="#4E7FF9"
|
||||||
|
cancelColor="#757575"
|
||||||
|
title="上级角色"
|
||||||
|
titleColor="#757575"
|
||||||
|
></rider-tree>
|
||||||
|
<!-- 菜单权限 -->
|
||||||
|
<rider-tree
|
||||||
|
ref="menuPicker"
|
||||||
|
:range="menuTreeList"
|
||||||
|
@cancel="$refs.menuPicker._hide()"
|
||||||
|
@confirm="onMenuConfirm"
|
||||||
|
idKey="id"
|
||||||
|
nameKey="title"
|
||||||
|
:multiple="true"
|
||||||
|
:cascade="true"
|
||||||
|
:foldAll="true"
|
||||||
|
confirmColor="#4E7FF9"
|
||||||
|
cancelColor="#757575"
|
||||||
|
title="菜单权限"
|
||||||
|
titleColor="#757575"
|
||||||
|
></rider-tree>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import riderCurd from '@/components/rider-crud/index'
|
||||||
|
import riderTree from '@/components/rider-crud/components/tree-picker'
|
||||||
|
import { getList, add, update, remove, roleTree, menuTree, menuTreeKey, grant } from '@/api/system/role.js'
|
||||||
|
import { tenantSelect } from '@/api/system/tenant.js'
|
||||||
|
import { getDicLabel } from '@/components/rider-crud/util/tool.js'
|
||||||
|
export default {
|
||||||
|
components: { riderCurd, riderTree },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
checkedSwitch: false,
|
||||||
|
form: {},
|
||||||
|
formLabel: {},
|
||||||
|
list: [],
|
||||||
|
params: {
|
||||||
|
current: 1,
|
||||||
|
size: 10
|
||||||
|
},
|
||||||
|
readonly: false, // 查看时控制表单只读
|
||||||
|
loadStatus: 'loadmore', // 列表加载状态
|
||||||
|
option: {
|
||||||
|
navTitle: '角色管理', //标题
|
||||||
|
manageBtn: true, // 右上角管理按钮,默认不显示
|
||||||
|
searchShow: true, //是否显示搜索,默认不显示
|
||||||
|
labelWidth: 160, //form表单lable宽度, 默认160,单位rpx
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
label: '角色名称',
|
||||||
|
prop: 'roleName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属租户',
|
||||||
|
prop: 'tenantName'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '角色别名',
|
||||||
|
prop: 'roleAlias'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '角色排序',
|
||||||
|
prop: 'sort'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
name: '编辑', // 操作名称
|
||||||
|
icon: 'edit-pen', //操作图标,有图标文字不显示
|
||||||
|
color: '#333', // 字体颜色
|
||||||
|
fontsize: 30, //字体大小,单位rpx
|
||||||
|
width: 40, // 宽度,单位px
|
||||||
|
background: '#fff' // 菜单按钮背景色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '删除',
|
||||||
|
icon: 'trash',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '菜单权限',
|
||||||
|
icon: 'setting',
|
||||||
|
color: '#333',
|
||||||
|
fontsize: 30,
|
||||||
|
width: 40,
|
||||||
|
background: '#fff'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
roleName: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
|
||||||
|
roleAlias: [{ required: true, message: '请输入角色别名', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入角色排序', trigger: 'blur', type: 'number' }]
|
||||||
|
},
|
||||||
|
tenantList: [],
|
||||||
|
roleTreeList: [],
|
||||||
|
menuTreeList: [],
|
||||||
|
menuCheckIds: [],
|
||||||
|
roleIds: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onReady() {
|
||||||
|
this.getTenant().then(() => {
|
||||||
|
this.getList(true)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
onReachBottom() {
|
||||||
|
if (this.loadStatus == 'nomore') return
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取列表
|
||||||
|
getList(override = false) {
|
||||||
|
if (override) {
|
||||||
|
this.params.current = 1
|
||||||
|
}
|
||||||
|
const { size } = this.params
|
||||||
|
getList(this.params)
|
||||||
|
.then(res => {
|
||||||
|
const records = res.data
|
||||||
|
if (records.length < size) this.loadStatus = 'nomore'
|
||||||
|
else this.loadStatus = 'loadmore'
|
||||||
|
if (override) {
|
||||||
|
this.list = records
|
||||||
|
} else {
|
||||||
|
this.list = this.list.concat(records)
|
||||||
|
}
|
||||||
|
if (this.list && this.list.length > 0) {
|
||||||
|
this.list = this.filterList(this.list)
|
||||||
|
}
|
||||||
|
this.params.current++
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
uni.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
filterList(list) {
|
||||||
|
if (!list || list.length == 0) return list
|
||||||
|
list.forEach(e => {
|
||||||
|
e.tenantName = getDicLabel(e.tenantId, this.tenantList, { label: 'tenantName', value: 'tenantId' })
|
||||||
|
if (e.children) this.filterList(e.children)
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
},
|
||||||
|
// 租户类型
|
||||||
|
getTenant() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
roleTree().then(res => {
|
||||||
|
this.roleTreeList = res.data
|
||||||
|
})
|
||||||
|
tenantSelect().then(res => {
|
||||||
|
this.tenantList = res.data
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取菜单权限内容
|
||||||
|
getMenu(roleIds) {
|
||||||
|
menuTreeKey({ roleIds }).then(res => {
|
||||||
|
this.menuCheckIds = res.data.menu
|
||||||
|
})
|
||||||
|
menuTree().then(res => {
|
||||||
|
this.recursion(this.menuCheckIds, res.data.menu)
|
||||||
|
this.menuTreeList = res.data.menu
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.menuPicker._show()
|
||||||
|
}, 10)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 递归
|
||||||
|
recursion(arr, menu) {
|
||||||
|
menu.forEach(e => {
|
||||||
|
if (arr.includes(e.id)) e.checked = true
|
||||||
|
if (e.hasChildren || (e.children && e.children.length > 0)) {
|
||||||
|
this.recursion(arr, e.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 菜单权限勾选回调
|
||||||
|
onMenuConfirm(e) {
|
||||||
|
let arr = []
|
||||||
|
e.forEach(e => {
|
||||||
|
arr.push(e.id)
|
||||||
|
})
|
||||||
|
const params = {
|
||||||
|
apiScopeIds: [],
|
||||||
|
dataScopeIds: [],
|
||||||
|
roleIds: [this.roleIds],
|
||||||
|
menuIds: arr
|
||||||
|
}
|
||||||
|
grant(params).then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: '操作成功'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//机构选择回调
|
||||||
|
onTreeConfirm(e) {
|
||||||
|
this.$set(this.form, 'parentId', e[0].id)
|
||||||
|
this.$set(this.formLabel, 'parentName', e[0].name)
|
||||||
|
},
|
||||||
|
// 搜索 (自行配置搜索内容)
|
||||||
|
onSearch(val) {
|
||||||
|
this.params = {
|
||||||
|
current: 1,
|
||||||
|
size: 10,
|
||||||
|
roleName: val
|
||||||
|
}
|
||||||
|
this.getList(true)
|
||||||
|
},
|
||||||
|
// 左滑按钮点击
|
||||||
|
onActionClick({ index, data, action, done }) {
|
||||||
|
const { name } = action
|
||||||
|
console.log(name, index)
|
||||||
|
switch (name) {
|
||||||
|
case '新增':
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '删除':
|
||||||
|
this.onRemove(data.id)
|
||||||
|
break
|
||||||
|
case '查看':
|
||||||
|
this.readonly = true
|
||||||
|
case '编辑':
|
||||||
|
this.$set(this.formLabel, 'parentName', data.parentName)
|
||||||
|
done()
|
||||||
|
break
|
||||||
|
case '菜单权限':
|
||||||
|
this.roleIds = data.id
|
||||||
|
this.getMenu(data.id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (['删除', '编辑'].includes(name)) this.$refs['crud'].hideChildren()
|
||||||
|
},
|
||||||
|
// 删除
|
||||||
|
onRemove(id) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确定要删除吗?',
|
||||||
|
success: action => {
|
||||||
|
if (action.confirm) {
|
||||||
|
remove(id).then(() => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '删除成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs['crud'].allCheckHide(false)
|
||||||
|
}, 100)
|
||||||
|
// #ifdef APP
|
||||||
|
this.getList(true)
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 表单提交
|
||||||
|
onSubmit(form, action, unloading, done) {
|
||||||
|
if (action == '新增') {
|
||||||
|
add(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '新增成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
// this.category = ''
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
} else if (action == '编辑') {
|
||||||
|
update(form)
|
||||||
|
.then(res => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '编辑成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
// this.category = ''
|
||||||
|
done()
|
||||||
|
uni.startPullDownRefresh({})
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
unloading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.nav-right {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-right: 24rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
|
||||||
|
<!-- 蓝色头部信息区 -->
|
||||||
|
<view class="header-section">
|
||||||
|
<view class="serial-no">流水号:{{orderInfo.code}}</view>
|
||||||
|
<view class="time-info">{{orderInfo.bookingTime}}</view>
|
||||||
|
<view class="project-info"> {{orderInfo.itemName}} </view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 取号信息卡片 -->
|
||||||
|
<view class="info-card new-card" v-if="isTicketInfoShow">
|
||||||
|
<view class="ticket_status">无感取号成功</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">排队号</text>
|
||||||
|
<text class="info-value">{{ticketInfo.queueNum}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">窗口号</text>
|
||||||
|
<text class="info-value">{{ticketInfo.counterlist}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 详情信息卡片 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">预约大厅</text>
|
||||||
|
<text class="info-value">广西区直住房保障中心</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">预约部门</text>
|
||||||
|
<text class="info-value">{{orderInfo.deptName}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">姓名</text>
|
||||||
|
<text class="info-value">{{ userinfo.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">手机号</text>
|
||||||
|
<text class="info-value">{{ userinfo.phone }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">证件类型</text>
|
||||||
|
<text class="info-value">身份证</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">证件号码</text>
|
||||||
|
<text class="info-value">{{ userinfo.idCard }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 取消预约按钮 -->
|
||||||
|
<view class="btn-wrap">
|
||||||
|
<button class="btn-cancel" v-if="orderInfo.status==1" @click="handleCancel">取消预约</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
getDetail,
|
||||||
|
getUserInfo,
|
||||||
|
cancel,
|
||||||
|
getIsSuccessTicket
|
||||||
|
} from '@/api/reserve.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 可通过页面传参动态获取以下数据
|
||||||
|
isTicketInfoShow: false,
|
||||||
|
ticketInfo: {},
|
||||||
|
orderInfo: {},
|
||||||
|
userinfo: {},
|
||||||
|
id: '',
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
this.id = options.id
|
||||||
|
this.getTicketInfo()
|
||||||
|
this.getUserInfo()
|
||||||
|
this.getDetail()
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 取号详情
|
||||||
|
getTicketInfo() {
|
||||||
|
getIsSuccessTicket({
|
||||||
|
yyNo: this.id
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code) {
|
||||||
|
this.isTicketInfoShow = Object.keys(res.data).length > 0 ? true : false
|
||||||
|
this.ticketInfo = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 预约详情
|
||||||
|
getDetail() {
|
||||||
|
getDetail({
|
||||||
|
id: this.id
|
||||||
|
}).then(res => {
|
||||||
|
this.orderInfo = res.data
|
||||||
|
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 个人信息详情
|
||||||
|
getUserInfo() {
|
||||||
|
getUserInfo().then(res => {
|
||||||
|
this.userinfo = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 返回上一页
|
||||||
|
handleGoBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
// 取消预约
|
||||||
|
handleCancel() {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要取消该预约吗?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
cancel({
|
||||||
|
id: this.orderInfo.id
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '取消成功',
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1 // 返回的页面数
|
||||||
|
})
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局容器 */
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 蓝色头部信息区 */
|
||||||
|
.header-section {
|
||||||
|
width: 100%;
|
||||||
|
background: linear-gradient(to right, rgba(75, 112, 252, 1), rgba(67, 195, 252, 1));
|
||||||
|
padding: 40rpx 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.serial-no {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-info {
|
||||||
|
font-size: 38rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-info {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
line-height: 1.5;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 信息卡片 */
|
||||||
|
.info-card {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
margin: 20rpx 30rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-card {
|
||||||
|
padding-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket_status {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 10rpx 32rpx;
|
||||||
|
width: fit-content;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
color: rgba(3, 195, 106, 1);
|
||||||
|
background-color: rgba(220, 255, 239, 1);
|
||||||
|
border-radius: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
width: 220rpx;
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333333;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 34rpx;
|
||||||
|
color: #333333;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 取消预约按钮 */
|
||||||
|
.btn-wrap {
|
||||||
|
padding: 20rpx 30rpx 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
width: 100%;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(255, 239, 239, 1);
|
||||||
|
color: rgba(244, 54, 54, 1);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(255, 195, 195, 1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,204 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 预约列表 -->
|
||||||
|
<view class="list-container">
|
||||||
|
<!-- 预约成功状态 -->
|
||||||
|
<view class="reserve-item" v-for="(item, index) in successList" :key="`success-${index}`">
|
||||||
|
<view class="item-header">
|
||||||
|
<text class="item-time">{{ item.bookingTime }}</text>
|
||||||
|
<text
|
||||||
|
:class="['status', item.status == 1 ? 'success' : 'canceled']">{{ item.status == 1 ? '预约成功' : '已取消' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="item-content">
|
||||||
|
<text class="item-project">{{ item.itemName }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="item-btns">
|
||||||
|
<button class="btn-cancel" v-if="item.status == 1" @click="handleCancel(item)">取消预约</button>
|
||||||
|
<button class="btn-cancel" v-if="item.status == 4">{{getStatus(item.status)}}</button>
|
||||||
|
<button class="btn-detail" @click="handleDetail(item)">查看详情</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<view class="empty-tip" v-if="successList.length === 0"> 暂无预约记录 </view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
getUserInfo,
|
||||||
|
myReserve,
|
||||||
|
cancel
|
||||||
|
} from '@/api/reserve.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 预约成功列表(和设计图完全一致)
|
||||||
|
successList: [],
|
||||||
|
userinfo: {},
|
||||||
|
statusList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.getUserInfo()
|
||||||
|
this.statusList = uni.getStorageSync('statusList');
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getStatus(code){
|
||||||
|
return this.statusList.find(item=>item.dictKey == code)?.dictValue
|
||||||
|
},
|
||||||
|
getUserInfo() {
|
||||||
|
getUserInfo().then(res => {
|
||||||
|
this.userinfo = res.data
|
||||||
|
this.getList()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
let params = {
|
||||||
|
size: 10,
|
||||||
|
current: 1,
|
||||||
|
idCard: this.userinfo.idCard,
|
||||||
|
descs: 'update_time'
|
||||||
|
}
|
||||||
|
myReserve(params).then(res => {
|
||||||
|
this.successList = res.data.records
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 返回上一页
|
||||||
|
handleGoBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
// 取消预约
|
||||||
|
handleCancel(item) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要取消该预约吗?',
|
||||||
|
success: res => {
|
||||||
|
if (res.confirm) {
|
||||||
|
cancel({
|
||||||
|
id: item.id
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.getList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 查看详情
|
||||||
|
handleDetail(item) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/myReserve/detail?id=${item.id}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 全局容器 */
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 列表容器 */
|
||||||
|
.list-container {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20rpx 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 预约项卡片 */
|
||||||
|
.reserve-item {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-time {
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 6rpx 16rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.success {
|
||||||
|
background-color: #e6f9e6;
|
||||||
|
color: #00b578;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.canceled {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-content {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-project {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-btns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
margin: 0;
|
||||||
|
width: 200rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
background-color: rgba(255, 239, 239, 1);
|
||||||
|
color: rgba(244, 54, 54, 1);
|
||||||
|
border-radius: 35rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(255, 195, 195, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-detail {
|
||||||
|
margin: 0;
|
||||||
|
width: 200rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
background-color: rgba(242, 247, 255, 1);
|
||||||
|
color: rgba(49, 134, 255, 1);
|
||||||
|
border-radius: 35rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态提示 */
|
||||||
|
.empty-tip {
|
||||||
|
text-align: center;
|
||||||
|
padding: 100rpx 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward" title="新闻详情页"
|
||||||
|
:background="{ background: '#fff' }" title-color="#000000">
|
||||||
|
<view class="right-nav" slot="right">
|
||||||
|
<image src="/static/images/news/search.png" class="icon icon-search" mode="widthFix"></image>
|
||||||
|
<image src="/static/images/news/menu.png" class="icon icon-menu" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</u-navbar>
|
||||||
|
|
||||||
|
<view class="header">
|
||||||
|
<image src="" class="avatar" mode=""></image>
|
||||||
|
<view class="info">
|
||||||
|
<view class="name">
|
||||||
|
中国空间站
|
||||||
|
<text class="tag">专栏作家</text>
|
||||||
|
</view>
|
||||||
|
<view class="date">11-12</view>
|
||||||
|
</view>
|
||||||
|
<view class="btn">+关注</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="title">
|
||||||
|
天舟五号创造多个航天新纪录
|
||||||
|
</view>
|
||||||
|
<view class="static">
|
||||||
|
<view class="left">
|
||||||
|
<view class="block">
|
||||||
|
<image src="/static/images/news/gf.png" class="gf"></image>
|
||||||
|
官方
|
||||||
|
</view>
|
||||||
|
<view class="block">
|
||||||
|
<image src="/static/images/news/x.png" class="gf"></image>
|
||||||
|
焦点新闻
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="right">
|
||||||
|
<image src="/static/images/news/l.png" class="l" mode="widthFix"></image>
|
||||||
|
66666
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="detail">
|
||||||
|
<u-parse :html="content"></u-parse>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="footer">
|
||||||
|
<input type="text" value="" placeholder="说点什么..." class="ipt" />
|
||||||
|
<view class="control">
|
||||||
|
<view class="block">
|
||||||
|
<image src="/static/images/news/c.png" class="icon c" mode="widthFix"></image>
|
||||||
|
458
|
||||||
|
</view>
|
||||||
|
<view class="block">
|
||||||
|
<image src="/static/images/news/s.png" class="icon s" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
<view class="block">
|
||||||
|
<image src="/static/images/news/t.png" class="icon t" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
content: `<p>在北京航天飞行控制中心拍摄的天舟五号货运飞船与空间站组合体完成自主快速交会对接示意图。孙丰晓摄(新华社发)</p>
|
||||||
|
<p>北京时间2022年11月12日10时03分,在文昌航天发射场,搭载天舟五号货运飞船的长征七号遥六运载火箭点火发射,将天舟五号货运飞船送入预定轨道。随后,天舟五号货运飞船与在轨运行的空间站组合体进行自主快速交会对接,中国航天员首次在空间站迎接货运飞船来访。</p>
|
||||||
|
<p>朝着在距离地面约400公里轨道上运行的中国空间站组合体,天舟五号首次实现2小时自主快速交会对接,创造世界纪录。这一技术突破对于提升我国空间交会对接水平,提升空间站任务应急物资补给能力具有重要意义。</p>
|
||||||
|
<p>空间站阶段最快交会对接,让人类航天器交会对接用时进入“2小时”时代。</p>
|
||||||
|
<p>此次任务是中国空间站“T”字基本构型在轨组装完成后,“太空快递”首次送达,执行运输任务的仍是长七火箭。</p>`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
padding: 0 0 150rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-nav {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 40rpx;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
&-search {
|
||||||
|
width: 40rpx;
|
||||||
|
margin-right: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-menu {
|
||||||
|
width: 40rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 44rpx;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 69rpx;
|
||||||
|
height: 69rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #69b0ff;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 14rpx;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 36rpx;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8rpx 10rpx;
|
||||||
|
font-size: 14rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4cbeca;
|
||||||
|
line-height: 21rpx;
|
||||||
|
border: 1px solid #0bb9c8;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #a3a3a3;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 8rpx 19rpx;
|
||||||
|
background: #e6e6e6;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4cbeca;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 44rpx;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 47rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.static {
|
||||||
|
margin-top: 34rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.left,
|
||||||
|
.right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left {
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #787878;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
.gf {
|
||||||
|
width: 24rpx;
|
||||||
|
height: 24rpx;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #787878;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
.l {
|
||||||
|
width: 25rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 6rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 47rpx;
|
||||||
|
margin-top: 50rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 999;
|
||||||
|
height: 100rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #ffffff;
|
||||||
|
|
||||||
|
.ipt {
|
||||||
|
width: 380rpx;
|
||||||
|
height: 77rpx;
|
||||||
|
background: #f7f7f7;
|
||||||
|
border-radius: 38px;
|
||||||
|
padding: 0 37rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
|
||||||
|
.block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c {
|
||||||
|
width: 41rpx;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s {
|
||||||
|
width: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t {
|
||||||
|
width: 31rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" title="新闻动态" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }"
|
||||||
|
title-color="#fff">
|
||||||
|
<image slot="right" src="/static/images/home/message.png" class="message-icon" mode="widthFix"></image>
|
||||||
|
</u-navbar>
|
||||||
|
|
||||||
|
<view class="tab">
|
||||||
|
<u-tabs :list="tabs" :is-scroll="false" :current="current" active-color="#69b0ff" inactive-color="#595959"
|
||||||
|
height="100" @change="change"></u-tabs>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<swiper id="swiperBox" :style="{ height: swiperHeight + 'px' }" :current="current" @change="tabsChange">
|
||||||
|
<swiper-item class="swiper-item" v-for="(pitem, pindex) in tabs" :key="pindex">
|
||||||
|
<scroll-view scroll-y style="width: 100%;height: 100%;" refresher-enabled
|
||||||
|
:refresher-triggered="pitem.triggered" @scrolltolower="onreachBottom"
|
||||||
|
@refresherrefresh="refresherrefresh(pindex)" @refresherrestore="refresherrestore(pindex)"
|
||||||
|
@refresherabort="refresherabort(pindex)">
|
||||||
|
<view class="content">
|
||||||
|
<navigator class="news" v-for="(item, index) in contentList[pindex].list" :key="index"
|
||||||
|
url="/pages/news/detail" hover-class="none">
|
||||||
|
<view class="head">
|
||||||
|
<image src="" class="avatar" mode=""></image>
|
||||||
|
<view class="info">
|
||||||
|
<view class="name">
|
||||||
|
中国空间站
|
||||||
|
<text class="tag">专栏作家</text>
|
||||||
|
</view>
|
||||||
|
<view class="date">11-12</view>
|
||||||
|
</view>
|
||||||
|
<u-icon name="arrow-right" size="35" color="#C5C5C5"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="des">
|
||||||
|
天舟五号创造多个航天新纪录。
|
||||||
|
</view>
|
||||||
|
</navigator>
|
||||||
|
<view class="nomore">
|
||||||
|
<u-loadmore :status="contentList[pindex].status" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
swiperHeight: 0,
|
||||||
|
tabs: [{
|
||||||
|
name: '互动',
|
||||||
|
triggered: false,
|
||||||
|
_triggered: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '动态',
|
||||||
|
triggered: false,
|
||||||
|
_triggered: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '通知',
|
||||||
|
triggered: false,
|
||||||
|
_triggered: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
contentList: [{
|
||||||
|
list: 8,
|
||||||
|
page: 1,
|
||||||
|
status: 'loadmore'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
list: 8,
|
||||||
|
page: 1,
|
||||||
|
status: 'loadmore'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
list: 8,
|
||||||
|
page: 1,
|
||||||
|
status: 'loadmore'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
current: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad() {},
|
||||||
|
onReady() {
|
||||||
|
let that = this;
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success(e) {
|
||||||
|
console.log(e);
|
||||||
|
let {
|
||||||
|
windowWidth,
|
||||||
|
windowHeight,
|
||||||
|
safeArea
|
||||||
|
} = e;
|
||||||
|
const query = uni.createSelectorQuery().in(that);
|
||||||
|
query
|
||||||
|
.select('#swiperBox')
|
||||||
|
.boundingClientRect(data => {
|
||||||
|
that.swiperHeight = safeArea.bottom - data.top;
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onPullDownRefresh() {
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.stopPullDownRefresh();
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
tabsChange(e) {
|
||||||
|
this.current = e.detail.current;
|
||||||
|
},
|
||||||
|
refresherrefresh(index) {
|
||||||
|
console.log('自定义下拉刷新被触发');
|
||||||
|
let _this = this;
|
||||||
|
if (_this.tabs[index]._triggered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_this.tabs[index]._triggered = true;
|
||||||
|
//界面下拉触发,triggered可能不是true,要设为true
|
||||||
|
if (!_this.tabs[index].triggered) {
|
||||||
|
_this.tabs[index].triggered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
_this.tabs[index].triggered = false; //触发onRestore,并关闭刷新图标
|
||||||
|
_this.tabs[index]._triggered = false;
|
||||||
|
}, 10);
|
||||||
|
},
|
||||||
|
refresherrestore(index) {
|
||||||
|
console.log('自定义下拉刷新被复位');
|
||||||
|
let _this = this;
|
||||||
|
_this.tabs[index].triggered = false;
|
||||||
|
_this.tabs[index]._triggered = false;
|
||||||
|
},
|
||||||
|
refresherabort(index) {
|
||||||
|
console.log('自定义下拉刷新被中止 ');
|
||||||
|
let _this = this;
|
||||||
|
_this.tabs[index].triggered = false;
|
||||||
|
_this.tabs[index]._triggered = false;
|
||||||
|
},
|
||||||
|
// scroll-view到底部加载更多
|
||||||
|
onreachBottom() {
|
||||||
|
let current = this.current;
|
||||||
|
if (this.contentList[current].page >= 3) return;
|
||||||
|
this.contentList[current].status = 'loading';
|
||||||
|
setTimeout(() => {
|
||||||
|
this.contentList[current].page = ++this.contentList[current].page;
|
||||||
|
this.contentList[current].list += 10;
|
||||||
|
if (this.contentList[current].page >= 3)
|
||||||
|
this.contentList[current].status = 'nomore';
|
||||||
|
else this.contentList[current].status = 'loading';
|
||||||
|
}, 2000);
|
||||||
|
},
|
||||||
|
change(index) {
|
||||||
|
this.current = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.message-icon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 27rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
margin: 0 0 10rpx;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 0 150rpx;
|
||||||
|
|
||||||
|
.news {
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-bottom: 2rpx solid #e4e7ed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nomore {
|
||||||
|
padding: 30rpx 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news {
|
||||||
|
margin: 30rpx 30rpx 0;
|
||||||
|
padding: 0 0 30rpx;
|
||||||
|
|
||||||
|
.head {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 69rpx;
|
||||||
|
height: 69rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
// border: 1px solid #14b9c8;
|
||||||
|
border: 1px solid #5f88ff;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 14rpx;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 36rpx;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
margin-left: 15rpx;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8rpx 10rpx;
|
||||||
|
font-size: 14rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #69b0ff;
|
||||||
|
line-height: 21rpx;
|
||||||
|
border: 1px solid #69b0ff;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #a3a3a3;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.des {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 47rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-box {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 预约信息卡片 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">预约项目</text>
|
||||||
|
<text class="info-value">{{ itemData.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row split-row">
|
||||||
|
<text class="info-label">预约时间</text>
|
||||||
|
<text class="info-value">{{ reserveTime }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">预约大厅</text>
|
||||||
|
<text class="info-value">广西区直住房保障中心</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">预约部门</text>
|
||||||
|
<text class="info-value">{{ itemData.deptName }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 个人信息卡片 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">姓名</text>
|
||||||
|
<text class="info-value">{{ userinfo.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row split-row">
|
||||||
|
<text class="info-label">手机号</text>
|
||||||
|
<text class="info-value">{{ userinfo.phone }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">证件类型</text>
|
||||||
|
<text class="info-value">身份证</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">证件号码</text>
|
||||||
|
<text class="info-value">{{ userinfo.idCard }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部按钮栏 -->
|
||||||
|
<view class="btn-bar">
|
||||||
|
<button class="btn-back" @click="handleGoBack">返回</button>
|
||||||
|
<button class="btn-confirm" @click="handleConfirm">确认预约</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
getUserInfo,
|
||||||
|
submit
|
||||||
|
} from '@/api/reserve.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
userinfo: {},
|
||||||
|
itemData: {},
|
||||||
|
reserveTime: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
this.itemData = JSON.parse(decodeURIComponent(options.data))
|
||||||
|
this.reserveTime = options.time
|
||||||
|
// this.userinfo = this.$store.state.userInfo
|
||||||
|
this.getUserInfo()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 返回上一页
|
||||||
|
handleGoBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
getUserInfo(){
|
||||||
|
getUserInfo().then(res=>{
|
||||||
|
this.userinfo = res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 确认预约
|
||||||
|
handleConfirm() {
|
||||||
|
const params = {
|
||||||
|
userId: this.userinfo.id,
|
||||||
|
applicant: this.userinfo.name,
|
||||||
|
phone: this.userinfo.phone,
|
||||||
|
idCard: this.userinfo.idCard,
|
||||||
|
itemId: this.itemData.id,
|
||||||
|
itemName: this.itemData.name,
|
||||||
|
deptId: this.itemData.deptId,
|
||||||
|
bookingDate: this.reserveTime.slice(0, 10),
|
||||||
|
timeSlot: this.reserveTime.slice(11),
|
||||||
|
}
|
||||||
|
|
||||||
|
submit(params).then(res => {
|
||||||
|
if (res.code == 200) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '预约成功!',
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/home/home'
|
||||||
|
})
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
}).catch(err => {})
|
||||||
|
|
||||||
|
|
||||||
|
// 可在此处添加跳转至预约成功页/首页逻辑
|
||||||
|
// uni.reLaunch({ url: '/pages/index/index' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 全局容器 */
|
||||||
|
.container {
|
||||||
|
min-height: 92vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 信息卡片 */
|
||||||
|
.info-card {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
margin: 20rpx 30rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-row {
|
||||||
|
border-bottom: 1rpx solid #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
width: 220rpx;
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333333;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 34rpx;
|
||||||
|
color: #333333;
|
||||||
|
text-align: right;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部按钮栏 */
|
||||||
|
.btn-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: 20rpx 30rpx 40rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
gap: 30rpx;
|
||||||
|
margin-top: auto;
|
||||||
|
box-shadow: 0 -8rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back {
|
||||||
|
flex: 1;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(242, 247, 255, 1);
|
||||||
|
color: rgba(49, 134, 255, 1);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-confirm {
|
||||||
|
flex: 2;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(49, 134, 255, 1);
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 顶部Tab切换 -->
|
||||||
|
<view class="tab-bar">
|
||||||
|
<view class="tab-item" :class="{ active: activeTab === 'department' }" @click="switchTab('department')">
|
||||||
|
单位预约 </view>
|
||||||
|
<view class="tab-item" :class="{ active: activeTab === 'person' }" @click="switchTab('person')"> 个人预约
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<view class="search-bar">
|
||||||
|
<view class="search-input-wrap">
|
||||||
|
<view class="search-icon"></view>
|
||||||
|
<input class="search-input" v-model="searchKeyword" clearable placeholder="请输入关键字搜索"
|
||||||
|
placeholder-class="placeholder-class" @confirm="handleSearch" />
|
||||||
|
</view>
|
||||||
|
<button class="search-btn" @click="handleSearch">搜索</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 部门列表 -->
|
||||||
|
<!-- <view class="list-container">
|
||||||
|
<view v-if="departmentList.length > 0">
|
||||||
|
<view class="list-item" v-for="(item, index) in departmentList" :key="index"
|
||||||
|
@click="handleDeptClick(item)">
|
||||||
|
<view class="item-left">
|
||||||
|
<view class="dot"></view>
|
||||||
|
<text class="item-text">{{ item.deptName }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="arrow"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else class="empty-tip">暂无事项数据</view>
|
||||||
|
</view> -->
|
||||||
|
|
||||||
|
<!-- 事项列表 -->
|
||||||
|
<view class="list-container">
|
||||||
|
<view v-if="itemList.length > 0">
|
||||||
|
<view class="list-item" v-for="(item, index) in itemList" :key="index" @click="handleItemClick(item)">
|
||||||
|
<view class="item-left">
|
||||||
|
<view class="dot"></view>
|
||||||
|
<text class="item-text">{{ item.name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="arrow"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
deptList,
|
||||||
|
itemList
|
||||||
|
} from '@/api/reserve.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeTab: 'department', // 当前激活的Tab:department-部门预约,person-事项预约
|
||||||
|
searchKeyword: '', // 搜索关键词
|
||||||
|
deptId: '',
|
||||||
|
// 部门列表(和设计图完全一致)
|
||||||
|
departmentList: [],
|
||||||
|
itemList: [],
|
||||||
|
type: 2 // 1个人, 2单位
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
if (option.id) {
|
||||||
|
this.deptId = option.id
|
||||||
|
// this.switchTab('person')
|
||||||
|
} else {
|
||||||
|
// this.getDeptList()
|
||||||
|
}
|
||||||
|
this.getItemList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// Tab切换
|
||||||
|
switchTab(tab) {
|
||||||
|
if (this.activeTab === tab) return
|
||||||
|
|
||||||
|
if (tab == 'department') {
|
||||||
|
// this.getDeptList()
|
||||||
|
this.type = 2
|
||||||
|
} else {
|
||||||
|
this.type = 1
|
||||||
|
}
|
||||||
|
this.activeTab = tab
|
||||||
|
this.searchKeyword = '' // 切换Tab清空搜索
|
||||||
|
this.getItemList()
|
||||||
|
// this.deptId = ''
|
||||||
|
},
|
||||||
|
// 搜索事件
|
||||||
|
handleSearch() {
|
||||||
|
// if (this.activeTab == 'department') {
|
||||||
|
// // this.getDeptList()
|
||||||
|
// } else {}
|
||||||
|
this.getItemList()
|
||||||
|
},
|
||||||
|
// 部门列表项点击事件
|
||||||
|
handleDeptClick(item) {
|
||||||
|
this.deptId = item.id
|
||||||
|
this.switchTab('person')
|
||||||
|
},
|
||||||
|
// 事项列表项点击事件
|
||||||
|
handleItemClick(item) {
|
||||||
|
const data = JSON.stringify(item)
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/reserve/notice?data=${encodeURIComponent(data)}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取部门列表
|
||||||
|
getDeptList() {
|
||||||
|
let params = {
|
||||||
|
size: 10,
|
||||||
|
current: 1,
|
||||||
|
status: 1,
|
||||||
|
deptName: this.searchKeyword
|
||||||
|
}
|
||||||
|
deptList(params).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.departmentList = res.data.records.filter(item => item.parentId != 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取事项列表
|
||||||
|
getItemList() {
|
||||||
|
// type:1个人, 2单位
|
||||||
|
let params = {
|
||||||
|
size: 10,
|
||||||
|
current: 1,
|
||||||
|
status: 1,
|
||||||
|
// deptId: this.deptId || '',
|
||||||
|
itemType: this.type,
|
||||||
|
name: this.searchKeyword
|
||||||
|
}
|
||||||
|
itemList(params).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.itemList = res.data.records
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局容器 */
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab栏 */
|
||||||
|
.tab-bar {
|
||||||
|
display: flex;
|
||||||
|
background-color: #ffffff;
|
||||||
|
height: 90rpx;
|
||||||
|
line-height: 90rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: 500;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item.active {
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item.active::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 120rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
background-color: #409eff;
|
||||||
|
border-radius: 3rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索栏 */
|
||||||
|
.search-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 30rpx;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
gap: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrap {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
padding: 0 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23999999"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>');
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #333333;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-class {
|
||||||
|
color: #999999;
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
width: 140rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
background: linear-gradient(to left, rgba(49, 134, 255, 1), rgba(21, 167, 255, 1));
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 列表容器 */
|
||||||
|
.list-container {
|
||||||
|
padding: 0 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(to bottom, rgba(49, 134, 255, 1), rgba(21, 167, 255, 1));
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
font-size: 34rpx;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
border-right: 4rpx solid #165dff;
|
||||||
|
border-top: 4rpx solid #165dff;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 空状态提示 */
|
||||||
|
.empty-tip {
|
||||||
|
text-align: center;
|
||||||
|
padding: 100rpx 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<!-- 协议内容区域 -->
|
||||||
|
<view class="agreement-content">
|
||||||
|
<view class="article" v-html="article"> </view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部按钮栏 -->
|
||||||
|
<view class="btn-bar">
|
||||||
|
<button class="btn-back" @click="handleGoBack">返回</button>
|
||||||
|
<button class="btn-confirm" @click="handleConfirm">确定预约</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { noticeData } from '@/api/reserve.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ConfirmPage',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
article: '',
|
||||||
|
itemData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad(options) {
|
||||||
|
this.itemData = JSON.parse(decodeURIComponent(options.data))
|
||||||
|
this.getNotice()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 返回上一页
|
||||||
|
handleGoBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
// 确定预约
|
||||||
|
handleConfirm() {
|
||||||
|
const data = JSON.stringify(this.itemData)
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/reserve/timeSelect?data=${encodeURIComponent(data)}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getNotice() {
|
||||||
|
let params = {
|
||||||
|
descs: 'update_time',
|
||||||
|
size: 10,
|
||||||
|
current: 1,
|
||||||
|
deptId: this.itemData.id
|
||||||
|
}
|
||||||
|
noticeData(params).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.article = res.data.records[0].content
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
/* 🔥 uni-app 必须加这个,页面高度才会生效 */
|
||||||
|
// page {
|
||||||
|
// height: 100%;
|
||||||
|
// }
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 最外层 flex 容器 */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
/* 兼容更好 */
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区域:自动占满剩余高度 + 滚动 */
|
||||||
|
.agreement-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 40rpx 30rpx;
|
||||||
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部按钮:固定在最下方,不使用 absolute */
|
||||||
|
.btn-bar {
|
||||||
|
display: flex;
|
||||||
|
padding: 20rpx 30rpx 40rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
gap: 30rpx;
|
||||||
|
border-top: 1rpx solid #eee;
|
||||||
|
box-shadow: 0 -8rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back {
|
||||||
|
flex: 1;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(242, 247, 255, 1);
|
||||||
|
color: rgba(49, 134, 255, 1);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-confirm {
|
||||||
|
flex: 2;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(49, 134, 255, 1);
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,327 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
|
||||||
|
<!-- 信息栏 -->
|
||||||
|
<view class="info-bar">
|
||||||
|
<view class="info-title">住房档案变更(房屋坐落变更)</view>
|
||||||
|
<view class="info-dept">公积金管理中心</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 日历 -->
|
||||||
|
<view class="calendar-wrap">
|
||||||
|
<view class="calendar-header">
|
||||||
|
<text class="week-item" v-for="week in weekList" :key="week">{{ week }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="date-row" v-for="(row, index) in calendarList" :key="index">
|
||||||
|
<view class="date-item" :class="{
|
||||||
|
active: item && item.active,
|
||||||
|
has: item && item.isAvailable,
|
||||||
|
disabled: !item || !item.isAvailable
|
||||||
|
}" v-for="(item, idx) in row" :key="idx" @click="selectDate(item)">
|
||||||
|
|
||||||
|
<text class="date-num">{{ item ? getDay(item.date) : '无' }}</text>
|
||||||
|
<text class="date-status" v-if="item">{{ item.isAvailable ? '有' : '无' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 时段 -->
|
||||||
|
<view class="time-list">
|
||||||
|
<view class="time-item" :class="{ selected: item.selected, disabled: item.remainingCount <= 0 }"
|
||||||
|
v-for="item in currentTimeSlots" :key="item.time" @click="selectTime(item)">
|
||||||
|
<view>{{ item.time }}</view>
|
||||||
|
<view>可预约 {{ item.remainingCount }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部 -->
|
||||||
|
<view class="footer-bar">
|
||||||
|
<view class="selected-info">已选:{{ selectedDate }} {{ selectedTime }}</view>
|
||||||
|
<view class="btn-box">
|
||||||
|
<button class="btn-gray" @click="handleGoBack">返回</button>
|
||||||
|
<button class="btn-blue" @click="handleNext">下一步</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
availableDate
|
||||||
|
} from '@/api/reserve.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
weekList: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
|
||||||
|
dateList: [],
|
||||||
|
calendarList: [],
|
||||||
|
currentTimeSlots: [],
|
||||||
|
selectedDate: "",
|
||||||
|
selectedTime: "",
|
||||||
|
itemData: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
this.itemData = JSON.parse(decodeURIComponent(options.data))
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData() {
|
||||||
|
availableDate({
|
||||||
|
itemId: this.itemData.id
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.dateList = res.data
|
||||||
|
this.initCalendar()
|
||||||
|
// 兼容无数据/首条不可选情况
|
||||||
|
const firstAva = this.dateList.find(item => item.isAvailable)
|
||||||
|
firstAva && this.selectDate(firstAva)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 核心重写:100%贴合需求 - 按weekDayName对列+跨周换行+今日为起点前后空
|
||||||
|
initCalendar() {
|
||||||
|
// 初始化两行(最多跨周展示两行,满足业务场景)
|
||||||
|
const row1 = Array(7).fill(null) // 第一行(今日所在周)
|
||||||
|
const row2 = Array(7).fill(null) // 第二行(跨周后的下一周)
|
||||||
|
// 星期转列索引映射(固定匹配表头)
|
||||||
|
const weekToCol = {
|
||||||
|
"星期一": 0,
|
||||||
|
"星期二": 1,
|
||||||
|
"星期三": 2,
|
||||||
|
"星期四": 3,
|
||||||
|
"星期五": 4,
|
||||||
|
"星期六": 5,
|
||||||
|
"星期日": 6
|
||||||
|
}
|
||||||
|
// 今日是列表第一条,获取今日所在星期列,作为展示起点
|
||||||
|
const today = this.dateList[0]
|
||||||
|
if (!today) {
|
||||||
|
this.calendarList = [row1, row2]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const todayCol = weekToCol[today.weekDayName]
|
||||||
|
// 遍历所有日期,按规则分配到对应行/列
|
||||||
|
this.dateList.forEach(item => {
|
||||||
|
const col = weekToCol[item.weekDayName]
|
||||||
|
if (col === undefined) return
|
||||||
|
// 规则:今日所在列及右侧 → 第一行;今日所在列左侧(跨周)→ 第二行
|
||||||
|
if (col >= todayCol) {
|
||||||
|
row1[col] = item
|
||||||
|
} else {
|
||||||
|
row2[col] = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 最终日历列表(仅保留有数据的行,无数据则不展示)
|
||||||
|
this.calendarList = [row1]
|
||||||
|
if (row2.some(item => item)) {
|
||||||
|
this.calendarList.push(row2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getDay(date) {
|
||||||
|
if (!date) return "";
|
||||||
|
return date.split("-")[2];
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDate(date) {
|
||||||
|
const arr = date.split("-");
|
||||||
|
return arr[0] + "-" + arr[1] + "-" + arr[2];
|
||||||
|
},
|
||||||
|
|
||||||
|
selectDate(item) {
|
||||||
|
if (!item || !item.isAvailable) return;
|
||||||
|
this.selectedTime = ''
|
||||||
|
this.dateList.forEach(i => (i.active = false));
|
||||||
|
item.active = true;
|
||||||
|
this.selectedDate = this.formatDate(item.date);
|
||||||
|
this.currentTimeSlots = (item.timeSlots || []).map(t => {
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
selected: false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (this.currentTimeSlots.length > 0) {
|
||||||
|
this.selectTime(this.currentTimeSlots[0]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
selectTime(item) {
|
||||||
|
if (item.remainingCount <= 0) return;
|
||||||
|
this.currentTimeSlots.forEach(t => (t.selected = false));
|
||||||
|
item.selected = true;
|
||||||
|
this.selectedTime = item.time;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleGoBack() {
|
||||||
|
uni.navigateBack();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleNext() {
|
||||||
|
if (!this.selectedDate || !this.selectedTime) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "请选择完整",
|
||||||
|
icon: "none"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.stringify(this.itemData)
|
||||||
|
const time = this.selectedDate + " " + this.selectedTime
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/reserve/confirm?data=${encodeURIComponent(data)}&time=${time}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.container {
|
||||||
|
background: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-bar {
|
||||||
|
background: linear-gradient(90deg, rgba(49, 134, 255, 1), #53a8ff);
|
||||||
|
padding: 30rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-title {
|
||||||
|
font-size: 34rpx;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-dept {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-wrap {
|
||||||
|
background: #fff;
|
||||||
|
margin: 20rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
border: 2rpx solid rgba(49, 134, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-header {
|
||||||
|
display: flex;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-item {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-item {
|
||||||
|
flex: 1;
|
||||||
|
width: 100rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-item.has {
|
||||||
|
color: rgba(49, 134, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-item.active {
|
||||||
|
background: rgba(49, 134, 255, 1);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-item.disabled {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-num {
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-status {
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-list {
|
||||||
|
padding: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-item {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-item.selected {
|
||||||
|
background: #e8f3ff;
|
||||||
|
border: 2rpx solid rgba(49, 134, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-item.disabled {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20rpx 30rpx 40rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-info {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-gray {
|
||||||
|
flex: 1;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(242, 247, 255, 1);
|
||||||
|
color: rgba(49, 134, 255, 1);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-blue {
|
||||||
|
flex: 2;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
background-color: rgba(49, 134, 255, 1);
|
||||||
|
color: #ffffff;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
border: 2rpx solid rgba(208, 227, 255, 1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,357 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="editor_toolbox" :style="{ top: `${statusBarHeight}px` }">
|
||||||
|
<u-icon name="arrow-leftward" size="40rpx" color="#303133" @click="onSave"></u-icon>
|
||||||
|
<!-- <i class="iconfont icon-save" @tap="onSave" /> -->
|
||||||
|
<i class="iconfont icon-undo" data-method="undo" @tap="edit" />
|
||||||
|
<i class="iconfont icon-redo" data-method="redo" @tap="edit" />
|
||||||
|
<i class="iconfont icon-img" data-method="insertImg" @tap="edit" />
|
||||||
|
<i class="iconfont icon-video" data-method="insertVideo" @tap="edit" />
|
||||||
|
<i class="iconfont icon-link" data-method="insertLink" @tap="edit" />
|
||||||
|
<i class="iconfont icon-text" data-method="insertText" @tap="edit" />
|
||||||
|
<i class="iconfont icon-clear" @tap="clear" />
|
||||||
|
</view>
|
||||||
|
<view :style="{ paddingTop: `${statusBarHeight + 50}px` }">
|
||||||
|
<mp-html ref="article" container-style="padding:20px" :content="content" domain="" :editable="editable" @remove="remove" />
|
||||||
|
</view>
|
||||||
|
<block v-if="modal">
|
||||||
|
<view class="mask" />
|
||||||
|
<view class="modal">
|
||||||
|
<view class="modal_title">{{ modal.title }}</view>
|
||||||
|
<input class="modal_input" :value="modal.value" maxlength="-1" auto-focus @input="modalInput" />
|
||||||
|
<view class="modal_foot">
|
||||||
|
<view class="modal_button" @tap="modalCancel">取消</view>
|
||||||
|
<view class="modal_button" style="color:#576b95;border-left:1px solid rgba(0,0,0,.1)" @tap="modalConfirm">确定</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import mpHtml from '@/components/rider-crud/components/mp-html/mp-html'
|
||||||
|
import http from '@/http/api.js'
|
||||||
|
// 上传图片方法
|
||||||
|
function upload(src, type) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log('上传', type === 'img' ? '图片' : '视频', ':', src)
|
||||||
|
// resolve(src)
|
||||||
|
const params = {
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
fileType: 'image/video/audio', // 仅支付宝小程序,且必填。
|
||||||
|
// #endif
|
||||||
|
filePath: src,
|
||||||
|
name: 'file'
|
||||||
|
}
|
||||||
|
http.upload('/api/blade-resource/oss/endpoint/put-file', params).then(res => {
|
||||||
|
resolve(res.data.link)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 删除图片方法
|
||||||
|
function remove(src) {
|
||||||
|
console.log('删除图片:', src)
|
||||||
|
// 实际使用时,删除线上资源
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
content: null,
|
||||||
|
modal: null,
|
||||||
|
editable: true,
|
||||||
|
statusBarHeight: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
mpHtml
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
/**
|
||||||
|
* @description 设置获取链接的方法
|
||||||
|
* @param {String} type 链接的类型(img/video/audio/link)
|
||||||
|
* @param {String} value 修改链接时,这里会传入旧值
|
||||||
|
* @returns {Promise} 返回线上地址
|
||||||
|
* type 为音视频时可以返回一个数组作为源地址
|
||||||
|
* type 为 audio 时,可以返回一个 object,包含 src、name、author、poster 等字段
|
||||||
|
*/
|
||||||
|
this.$refs.article.getSrc = (type, value) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (type === 'img' || type === 'video') {
|
||||||
|
uni.showActionSheet({
|
||||||
|
itemList: ['本地选取', '远程链接'],
|
||||||
|
success: res => {
|
||||||
|
if (res.tapIndex === 0) {
|
||||||
|
// 本地选取
|
||||||
|
if (type === 'img') {
|
||||||
|
uni.chooseImage({
|
||||||
|
count: value === undefined ? 9 : 1, // 2.2.0 版本起插入图片时支持多张(修改图片链接时仅限一张)
|
||||||
|
success: res => {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
if (res.tempFilePaths.length == 1 && wx.editImage) {
|
||||||
|
// 单张图片时进行编辑
|
||||||
|
wx.editImage({
|
||||||
|
src: res.tempFilePaths[0],
|
||||||
|
complete: res2 => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '上传中'
|
||||||
|
})
|
||||||
|
upload(res2.tempFilePath || res.tempFilePaths[0], type).then(res => {
|
||||||
|
uni.hideLoading()
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// #endif
|
||||||
|
uni.showLoading({
|
||||||
|
title: '上传中'
|
||||||
|
})
|
||||||
|
;(async () => {
|
||||||
|
const arr = []
|
||||||
|
for (let item of res.tempFilePaths) {
|
||||||
|
// 依次上传
|
||||||
|
const src = await upload(item, type)
|
||||||
|
arr.push(src)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
})().then(res => {
|
||||||
|
uni.hideLoading()
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.chooseVideo({
|
||||||
|
success: res => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '上传中'
|
||||||
|
})
|
||||||
|
upload(res.tempFilePath, type).then(res => {
|
||||||
|
uni.hideLoading()
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 远程链接
|
||||||
|
this.callback = {
|
||||||
|
resolve,
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
this.$set(this, 'modal', {
|
||||||
|
title: (type === 'img' ? '图片' : '视频') + '链接',
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.callback = {
|
||||||
|
resolve,
|
||||||
|
reject
|
||||||
|
}
|
||||||
|
let title
|
||||||
|
if (type === 'audio') {
|
||||||
|
title = '音频链接'
|
||||||
|
} else if (type === 'link') {
|
||||||
|
title = '链接地址'
|
||||||
|
}
|
||||||
|
this.$set(this, 'modal', {
|
||||||
|
title,
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad(option) {
|
||||||
|
let that = this
|
||||||
|
that.content = option.data
|
||||||
|
// 获取高度 - 小程序设配
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: function(res) {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
that.statusBarHeight = Number(res.statusBarHeight) + Number(res.platform == 'ios' ? 44 : 48)
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
that.statusBarHeight = Number(res.statusBarHeight)
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 删除图片/视频/音频标签事件
|
||||||
|
remove(e) {
|
||||||
|
// 删除线上资源
|
||||||
|
remove(e.src)
|
||||||
|
},
|
||||||
|
// 处理模态框
|
||||||
|
modalInput(e) {
|
||||||
|
this.value = e.detail.value
|
||||||
|
},
|
||||||
|
modalConfirm() {
|
||||||
|
this.callback.resolve(this.value || this.modal.value || '')
|
||||||
|
this.$set(this, 'modal', null)
|
||||||
|
},
|
||||||
|
modalCancel() {
|
||||||
|
this.callback.reject()
|
||||||
|
this.$set(this, 'modal', null)
|
||||||
|
},
|
||||||
|
// 调用编辑器接口
|
||||||
|
edit(e) {
|
||||||
|
this.$refs.article[e.currentTarget.dataset.method]()
|
||||||
|
},
|
||||||
|
// 清空编辑器内容
|
||||||
|
clear() {
|
||||||
|
uni.showModal({
|
||||||
|
title: '确认',
|
||||||
|
content: '确定清空内容吗?',
|
||||||
|
success: res => {
|
||||||
|
if (res.confirm) this.$refs.article.clear()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 保存编辑器内容
|
||||||
|
onSave() {
|
||||||
|
setTimeout(() => {
|
||||||
|
var content = this.$refs.article.getContent()
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '是否保存当前内容返回上一级?',
|
||||||
|
confirmText: '保存',
|
||||||
|
cancelText: '不保存',
|
||||||
|
success: res => {
|
||||||
|
if (res.confirm) {
|
||||||
|
uni.$emit('richBack', content)
|
||||||
|
}
|
||||||
|
this.editable = false
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.editor_toolbox {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
background-color: #ededed;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'iconfont';
|
||||||
|
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAeYAAsAAAAADlAAAAdLAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCEAgqOYItrATYCJAMkCxQABCAFhG0HcBv/CzOjdoNyEiD7nwnxpstuRCLrGmPTaffv/hnWZJHUNtWZeOD/3t03mks73vmC/3jA8SRom0aatimgfv7d9M8lBEJCIHRBKua0E7EEOqedMBEJm8N7js0MWpgq9PlMkGcTsS8NgH3X/AEbFaFGZNFvH+xR2uYofWlu9NO9ypmTgvNlW8CitMbdT7rHpgAXaKxBOfzWBdQCFgyrMV3kKtMLUFGd7GEC0JSkACq79OKAIMbDAW2W48z1QESSiQsUARGRZFyYAZ0AR8Q1ogsAjs7vhy+UBQIgwhPwR83HdB4F7R6gR25M+CrAUEwAobtM6LuBBBRA1qlLZvYO80KFg8isxmImAH1xHwzc0UPpQ/ph9cNLD+8+cn/9mnAgGQwUGkVj0B1kUhL4EP94IgQIVeCoDc62pg7uyLCRwUMCauARlsQ0ElWAq5EoAV9CogB8FzYieLq7qQM0rM5DYAriAik/Li6hNpHBj2knBBuokIJWymUizhppEknSNKNTIHnPfnR5WRIjFnmB0MgyTh9CFr9W5WgCNNfq00hdfi0KEVVL7I0kQvMYjy8OUbDAQIFwzDiGGzMKX+/PVu1sih2FbLk8PneQ0e84zT9a9GckbXu06x/h1C0hw45Twmlb0BLgUtCw7qqMfsqCGhV6bZl8tzTOhwXIwI1ZQCJLIIvccUoHE88h4XC2eGu4M/1XNB3fedRypMHlpyhbEwA5zn0qQ+4JIFxpmvQRIqHR6kOYxT8yRF6DufwjDl1JEG+8Wqk8ej0Z33StarLSdvb0fhAL+06dIRXWc4EDCLccDJ7nRTRGNUgi5S3sUk8hG4BAIuuqdJzCcXaWtWpZK0O7I0Mqs9SeBk6HJs+pMZ3cqWSo18Up8nh2vcql1drvYnRZfFaWawwlbAjnNuUeD0fz47f2GNsa/fF7o5EiX96JqiMhfWMOZ3c32aoWarUuu1GgZb3ZijxTszPBoebYYVU51WtjNSTXad3ekZzB2YUmmynf7Frv87CjOrjBApsDIHqPD//DhUKGSMSAEKRwBgqH+XDUGI0YIlaOKiYk2EnSqUEWF7XAageI3OVCf/PhsDEaNSKnhrSzKBTiQlVdDbJsPEl0ONSUS4ssTnLO4dOJ8O/y7lwLIsG9w6MxwIZTFYojgSR8c7B6ksJqZ8UOB6W0ubb0SifPuQb42mUpNFyJuQI0OLvELTPRSN5ODs3CBUKIBoDa1xrz1K/SNy3fVPVDMKK2XqdM6a9QLFycnZWRVUJ89QUvJOjZoAOfr7zKhGDrb79CEfP5M8/DTEvPngRh8AWBr9OZ66+89rX3tVtZ8tVf0r2fhur6+fMn0ALooJU7KIuS79+fpFNWX018UNVONCAU6vv7QGWHX5rbxpdvCW5JI9sFt9aUVW1pjXfr1K+5X6dOeOsts8vm/p1Iq+glCpUiObh4EVm2JbClPL5V603DrqjoTQomnlFsolUURBISwDpcroJ7b0oA02NQonc6VOv1iZVzBiYiduCcysTgHXF6OAN6GftRd0b3kZV9q0+AxEQ+IRESEvhEqIl262o2d+ZSUQfnmQcNY2dMXbp06rKxDTkJDJeW6vN3QmnfdO+etSJLmp0tSazIHjphQaZo7r6Dq2MZ3eom36nkLlp5St+X1jcrBkv4xK/79qbGfer3tXOWL0+NzJUNjuev1m2r8TwarGszs8uaVXMJRufavYvjGRWXNvLMw4a6hqnTp+OWddN3rFg+ixl4/IR5XXolag7ZzhxpDtvDmd17wTeo3HzocG+79mhzQ6GYS6SY3AUFNu1aUC5jsE6YcVIdLZk+YIqhI161tOWSVwtt2jUJey9Kv5VI+tWYJCCe8U3j1Nhp6t/ry8zF48oidd2GdLkxpPOAeiG9UXgmkpyh9YWSltIkJvUm3/2XckNk/emn1TPGhuRv5ddp5qpQ5XLRDWCzQqyzQ4tWrMxPsIRfxsInjYr7g9evq5O7w5KQAvAPYk1YW0p4kkSoGpozaS3WThNOfixfE8B+wzrpbqcdWAzzu1akq+jGw+IgeIpNPUYoW30gqPdHzI3c6qeif0AMzVuoE4HK3keDt+KE/PXzUOM3K4anQW5D40VTGYGmWAAeCflDN7ulJpW9TyBKHUAklQgJIYOROQVQQamAKkJbaMrX9fKWFqYDBmUZgJkVDBDGXhBRCAKGcdEJJzg3AKfxAiSYgAHJgFrckJIVVqPJSTBWzCD5AKVcG5mmE7ftHW1TxhL2O+o/lEBlsJjO43U3rFG6OCU87VLVgBGu4Moeh2XJ4IVzTHXqVP1xNjNZp05TrlqTVkfBWC3zDJKPPaVcm611kvj5O9qmjKVgyI/9H0qg7cNiOq/AuKG60pBT6RyedqmUacDoLVzBlTKxFNUMPnu/HFOdugaV/jijqUxVNB2eqs41gtM3LCcta4sQhsQIRxIkRQSSIRLEim8daOMprvsqcXCDRdX2cFgMy8TbcsJh6vBNMY++jmv7bXgQHHmqWy0A')
|
||||||
|
format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
color: #303133;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'iconfont' !important;
|
||||||
|
font-size: 22px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-undo:before {
|
||||||
|
content: '\e607';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-redo:before {
|
||||||
|
content: '\e606';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-img:before {
|
||||||
|
content: '\e6e2';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-video:before {
|
||||||
|
content: '\e798';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-link:before {
|
||||||
|
content: '\e60d';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-text:before {
|
||||||
|
content: '\e6ce';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-clear:before {
|
||||||
|
content: '\e637';
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-save:before {
|
||||||
|
content: '\e501';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 模态框 */
|
||||||
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 16px;
|
||||||
|
right: 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_title {
|
||||||
|
padding: 32px 24px 16px;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_input {
|
||||||
|
display: block;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 0 24px 32px 24px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid #dfe2e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_foot {
|
||||||
|
display: flex;
|
||||||
|
line-height: 56px;
|
||||||
|
font-weight: 700;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal_button {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 蒙版 */
|
||||||
|
.mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: black;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="head">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-color="#fff" back-icon-size="35" :background="{ background: 'linear-gradient(90deg, #69b0ff, #5f88ff)' }" title="服务"
|
||||||
|
title-color="#fff"></u-navbar>
|
||||||
|
<view class="head-bg"></view>
|
||||||
|
<!-- 我的订阅 start -->
|
||||||
|
<view class="card sub">
|
||||||
|
<view class="title">我的订阅</view>
|
||||||
|
<view class="list">
|
||||||
|
<u-grid :col="4" :border="false">
|
||||||
|
<u-grid-item bg-color="transparent" v-for="(item, index) in subscribeList" :key="index">
|
||||||
|
<navigator url="" hover-class="none" class="nav-item">
|
||||||
|
<image :src="item.img" mode="widthFix" class="nav-item-img"></image>
|
||||||
|
<view class="nav-item-name">{{ item.name }}</view>
|
||||||
|
</navigator>
|
||||||
|
</u-grid-item>
|
||||||
|
</u-grid>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 我的订阅 end -->
|
||||||
|
|
||||||
|
<!-- 服务列表 start -->
|
||||||
|
<view class="card wrap" v-for="(item, index) in serviceList" :key="index">
|
||||||
|
<view class="title">{{item.name}}</view>
|
||||||
|
<view class="list">
|
||||||
|
<u-grid :col="4" :border="false">
|
||||||
|
<u-grid-item bg-color="transparent" v-for="(_item, _index) in item.list" :key="_index">
|
||||||
|
<navigator url="" hover-class="none" class="nav-item">
|
||||||
|
<image :src="_item.img" mode="widthFix" class="nav-item-img"></image>
|
||||||
|
<view class="nav-item-name">{{ _item.name }}</view>
|
||||||
|
</navigator>
|
||||||
|
</u-grid-item>
|
||||||
|
</u-grid>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 服务列表 end -->
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
fakeSubscribeList,
|
||||||
|
fakeServiceList,
|
||||||
|
} from "@/api/mock/service.js";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 我的订阅
|
||||||
|
subscribeList: [],
|
||||||
|
// 服务列表
|
||||||
|
serviceList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
// 后续将改为与后端联动
|
||||||
|
// 加载我的订阅数据
|
||||||
|
fakeSubscribeList().then(data => {
|
||||||
|
this.subscribeList = data;
|
||||||
|
})
|
||||||
|
// 加载服务集合数据
|
||||||
|
fakeServiceList().then(data => {
|
||||||
|
this.serviceList = data;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-bg {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
z-index: -1;
|
||||||
|
width: 750rpx;
|
||||||
|
height: 270rpx;
|
||||||
|
background: linear-gradient(90deg, #69b0ff, #5f88ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin: 30rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
margin-top: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub {
|
||||||
|
.title {
|
||||||
|
padding-top: 36rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #000000;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 135rpx;
|
||||||
|
height: 1rpx;
|
||||||
|
background: #e4e7ed;
|
||||||
|
margin: 0 17rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 135rpx;
|
||||||
|
height: 1rpx;
|
||||||
|
background: #e4e7ed;
|
||||||
|
margin: 0 17rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 0 0 30rpx;
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #131313;
|
||||||
|
line-height: 48rpx;
|
||||||
|
opacity: 0.77;
|
||||||
|
|
||||||
|
&-img {
|
||||||
|
width: 54rpx;
|
||||||
|
height: 54rpx;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-name {
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-family: PingFang SC;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #585b61;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
.title {
|
||||||
|
padding: 36rpx 16rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #000000;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 5rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
background: #3ac4d1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward"
|
||||||
|
back-icon-size="35" :background="{ background: '#fff' }" title="设置" title-color="#000">
|
||||||
|
</u-navbar>
|
||||||
|
<view class="u-demo">
|
||||||
|
<view class="u-demo-wrap">
|
||||||
|
<view class="u-demo-title">很快到来</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="head" :style="{height: `${headHeight}rpx`}">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="false" title="个人中心" :background="{ background: 'transprent' }" title-color="#FFFFFF">
|
||||||
|
<view @click="$u.func.route('/pages/system/setting')" slot="right">
|
||||||
|
<image src="/static/images/user/setting.png" class="set-icon" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</u-navbar>
|
||||||
|
<image src="/static/images/user/bg.png" class="head-bg" :style="{height: `${headHeight}rpx`}" />
|
||||||
|
|
||||||
|
<!-- 用户信息 -->
|
||||||
|
<view class="user-box">
|
||||||
|
<view class="left">
|
||||||
|
<image :src="userInfo.avatar" class="avatar" mode=""></image>
|
||||||
|
<view class="user-name">{{ userInfo.nick_name }}</view>
|
||||||
|
<view class="tag">{{ userInfo.tenant_id }}</view>
|
||||||
|
</view>
|
||||||
|
<view @click="$u.func.route('/pages/user/profile')" class="edit-btn">编辑资料</view>
|
||||||
|
</view>
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<view class="nav">
|
||||||
|
<navigator url="" hover-class="none" class="nav-item">
|
||||||
|
<image src="/static/images/user/n1.png" class="icon" mode=""></image>
|
||||||
|
<view class="name">我的消息</view>
|
||||||
|
</navigator>
|
||||||
|
<navigator url="" hover-class="none" class="nav-item">
|
||||||
|
<image src="/static/images/user/n2.png" class="icon" mode=""></image>
|
||||||
|
<view class="name">我的待办</view>
|
||||||
|
</navigator>
|
||||||
|
<navigator url="" hover-class="none" class="nav-item">
|
||||||
|
<image src="/static/images/user/n3.png" class="icon" mode=""></image>
|
||||||
|
<view class="name">我的地址</view>
|
||||||
|
</navigator>
|
||||||
|
<navigator url="" hover-class="none" class="nav-item">
|
||||||
|
<image src="/static/images/user/n4.png" class="icon" mode=""></image>
|
||||||
|
<view class="name">我的收藏</view>
|
||||||
|
</navigator>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 功能列表 -->
|
||||||
|
<view class="cell-box">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<u-cell-item title="我的评价">
|
||||||
|
<image slot="icon" src="/static/images/user/c1.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
<u-cell-item title="常见问题">
|
||||||
|
<image slot="icon" src="/static/images/user/c2.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
<u-cell-item title="客服中心" :border-bottom="false">
|
||||||
|
<image slot="icon" src="/static/images/user/c3.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
<view class="cell-box">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<u-cell-item title="推荐">
|
||||||
|
<image slot="icon" src="/static/images/user/c4.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
<u-cell-item title="评分">
|
||||||
|
<image slot="icon" src="/static/images/user/c5.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
<u-cell-item title="反馈">
|
||||||
|
<image slot="icon" src="/static/images/user/c6.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
<u-cell-item title="关于" :border-bottom="false">
|
||||||
|
<image slot="icon" src="/static/images/user/c7.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
<view class="cell-box">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<u-cell-item title="设置" :border-bottom="false" @click="$u.func.route('/pages/system/setting')">
|
||||||
|
<image slot="icon" src="/static/images/user/c8.png" class="icon" mode=""></image>
|
||||||
|
</u-cell-item>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
headHeight: 582
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setHeadHeight()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setHeadHeight() {
|
||||||
|
const that = this
|
||||||
|
// #ifndef H5
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: function(res) {
|
||||||
|
that.headHeight = Number(res.statusBarHeight) + Number(res.platform == 'ios' ? 44 : 48) + 582
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
min-height: 582rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #55A2F9;
|
||||||
|
|
||||||
|
.set-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 41rpx;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 35rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-bg {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
z-index: -1;
|
||||||
|
width: 750rpx;
|
||||||
|
height: 582rpx;
|
||||||
|
background: #55A2F9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 20rpx 0 64rpx;
|
||||||
|
margin-top: 36rpx;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 128rpx;
|
||||||
|
height: 128rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 5rpx 16rpx;
|
||||||
|
border: 1px solid #f5f5f5;
|
||||||
|
border-radius: 7rpx;
|
||||||
|
|
||||||
|
font-size: 19rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 300;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-btn {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
width: 165rpx;
|
||||||
|
height: 54rpx;
|
||||||
|
border: 2rpx solid #f5f5f5;
|
||||||
|
border-radius: 11rpx;
|
||||||
|
|
||||||
|
font-size: 27rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
display: flex;
|
||||||
|
//border-top: 2rpx solid #7dcdd6;
|
||||||
|
margin: 36rpx 38rpx 0;
|
||||||
|
padding: 36rpx 0 42rpx;
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
width: calc(100% / 4);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
font-size: 25rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 2rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 30rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 48rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
margin-bottom: 6rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-box {
|
||||||
|
background: #ffffff;
|
||||||
|
margin: 18rpx;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
margin-right: 22rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,213 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<u-navbar :is-fixed="false" :border-bottom="false" :is-back="true" back-icon-name="arrow-leftward" title="个人资料"
|
||||||
|
back-icon-size="35" :background="{ background: '#fff' }" title-color="#000">
|
||||||
|
<view class="complie" slot="right" @click="submit">完成</view>
|
||||||
|
</u-navbar>
|
||||||
|
|
||||||
|
<view class="content">
|
||||||
|
<view class="avatar">
|
||||||
|
<image :src="userInfo.avatar" class="avatar-image" mode=""></image>
|
||||||
|
<view class="a" @click="handleChooseImg">更换头像</view>
|
||||||
|
</view>
|
||||||
|
<view class="form">
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">昵称</view>
|
||||||
|
<input type="text" placeholder="请输入昵称" v-model="userInfo.nick_name" class="ipt"
|
||||||
|
placeholder-class="hold" />
|
||||||
|
</view>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">生日</view>
|
||||||
|
<picker mode="date" class="ipt" :class="{ hold: !detail.birthday }"
|
||||||
|
@change="changeDefaultPicker('birthday', $event)">
|
||||||
|
<view>{{ detail.birthday || '请选择生日' }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">性别</view>
|
||||||
|
<picker mode="selector" :range="sexPicker" range-key="name" class="ipt"
|
||||||
|
:class="{ hold: !detail.sex }" @change="changePicker('sex', $event)">
|
||||||
|
<view>{{ detail.sex === 1?'男':'女' || '请选择性别' }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">手机号</view>
|
||||||
|
<input type="number" placeholder="请填写手机号" v-model="detail.phone" class="ipt"
|
||||||
|
placeholder-class="hold" />
|
||||||
|
</view>
|
||||||
|
<view class="cell">
|
||||||
|
<view class="name">邮箱</view>
|
||||||
|
<input v-model="detail.email" class="ipt" placeholder-class="hold" />
|
||||||
|
</view>
|
||||||
|
<!--<view class="cell">
|
||||||
|
<view class="name">国家/地区</view>
|
||||||
|
<pickRegions :defaultRegion="detail.region" v-model="detail.region"
|
||||||
|
:class="{ hold: !detail.region, ipt: true }">
|
||||||
|
<view>{{ detail.region || '请选择国家/地区' }}</view>
|
||||||
|
</pickRegions>
|
||||||
|
</view>-->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- -->
|
||||||
|
<view class="back" @click="logout">退出登录</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import pickRegions from '@/components/pick-regions/pick-regions.vue';
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
pickRegions
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sexPicker: [{
|
||||||
|
name: '男'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '女'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
detail: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.$u.api.userInfo().then(data => {
|
||||||
|
console.log(data);
|
||||||
|
if (data.success) {
|
||||||
|
this.detail = data.data;
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
this.$u.func.showToast({
|
||||||
|
title: err,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
logout() {
|
||||||
|
this.$u.func.logout();
|
||||||
|
},
|
||||||
|
submit() {
|
||||||
|
let detail = this.detail
|
||||||
|
if (!detail.phone && !/^1\d{10}$/.test(detail.phone)) {
|
||||||
|
return uni.showToast({
|
||||||
|
title: '请输入正确的手机号',
|
||||||
|
duration: 2000,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(JSON.stringify(detail));
|
||||||
|
},
|
||||||
|
changeDefaultPicker(name, e) {
|
||||||
|
this.detail[name] = e.detail.value;
|
||||||
|
},
|
||||||
|
changePicker(name, e) {
|
||||||
|
this.detail[name] = this[`${name}Picker`][e.detail.value].name;
|
||||||
|
},
|
||||||
|
handleChooseImg() {
|
||||||
|
let that = this;
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1,
|
||||||
|
success(e) {
|
||||||
|
that.detail.avatar = e.tempFilePaths[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.container {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 0 0 200rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complie {
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 10rpx 20rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #5f88ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background-color: #ffffff;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #5f88ff;
|
||||||
|
.avatar-image {
|
||||||
|
width: 162rpx;
|
||||||
|
height: 162rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #82848a;
|
||||||
|
margin-bottom: 15rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
padding: 0 36rpx;
|
||||||
|
|
||||||
|
.cell {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 40rpx 0;
|
||||||
|
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666666;
|
||||||
|
|
||||||
|
&:not(:last-of-type) {
|
||||||
|
border-bottom: 2rpx solid #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ipt {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 40rpx;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 23rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hold {
|
||||||
|
font-size: 27rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #c8c8ce;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
text-align: center;
|
||||||
|
height: 109rpx;
|
||||||
|
background: #ffffff;
|
||||||
|
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-family: Source Han Sans CN;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #141414;
|
||||||
|
line-height: 109rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 607 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |