1.合并前段时间写的页面
@@ -24,6 +24,6 @@ const config = {
|
||||
}
|
||||
|
||||
// 设置后台接口服务的基础地址
|
||||
config.baseUrl = 'http://192.168.0.104:8080';
|
||||
config.baseUrl = 'http://tc.cqsznc.com:7080/api';
|
||||
|
||||
export default config;
|
@@ -12,11 +12,12 @@ const install = (Vue, vm) => {
|
||||
|
||||
|
||||
login: (params = {}) => vm.$u.post(config.adminPath+'/auth/login', params),
|
||||
getUserInfo: (params = {}) => vm.$u.get(config.adminPath+'/system/user/profile', params),
|
||||
|
||||
// 基础服务:登录登出、身份信息、菜单授权、切换系统、字典数据等
|
||||
lang: (params = {}) => vm.$u.get('/lang/'+params.lang),
|
||||
index: (params = {}) => vm.$u.get(config.adminPath+'/mobile/index', params),
|
||||
getUserInfo: (params = {}) => vm.$u.get(config.adminPath+'/mobile/user/getUserInfo', params),
|
||||
// getUserInfo: (params = {}) => vm.$u.get(config.adminPath+'/mobile/user/getUserInfo', params),
|
||||
// login: (params = {}) => vm.$u.post(config.adminPath+'/mobile/login/loginByPassword', params),
|
||||
sendCode: (params = {}) => vm.$u.post(config.adminPath+'/mobile/login/sendCode', params),
|
||||
registerUser: (params = {}) => vm.$u.post(config.adminPath+'/mobile/user/registerUser', params),
|
||||
|
@@ -30,10 +30,10 @@ const install = (Vue, vm) => {
|
||||
if (!req.header[ajaxHeader]){
|
||||
req.header[ajaxHeader] = 'json';
|
||||
}
|
||||
|
||||
console.log('t1', req.url);
|
||||
// 设定传递 Token 认证参数 aidex
|
||||
if (!req.header[sessionIdHeader] && vm.vuex_token){
|
||||
req.header[sessionIdHeader] = vm.vuex_token;
|
||||
if (req.url!="/auth/login"&&!req.header[sessionIdHeader] && vm.vuex_token){
|
||||
req.header[sessionIdHeader] = "Bearer "+vm.vuex_token;
|
||||
}
|
||||
|
||||
// 为节省流量,记住我数据不是每次都发送的,当会话失效后,尝试重试登录 aidex
|
||||
|
624
pages.json
@@ -2,207 +2,405 @@
|
||||
"easycom": {
|
||||
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/sys/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/login/forget",
|
||||
"style": {
|
||||
"navigationBarTitleText": "忘记密码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/login/reg",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册账号"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/msg/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/msg/form",
|
||||
"style": {
|
||||
"navigationBarTitleText": "查看详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/home/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作台",
|
||||
"navigationStyle": "custom" // 隐藏系统导航栏
|
||||
//案列页面
|
||||
// "pages": [
|
||||
// {
|
||||
// "path": "pages/sys/login/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "登录"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/login/forget",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "忘记密码"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/login/reg",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "注册账号"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/msg/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "消息"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/msg/form",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "查看详情"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/home/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "工作台",
|
||||
// "navigationStyle": "custom" // 隐藏系统导航栏
|
||||
|
||||
}
|
||||
},
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "我的",
|
||||
// "navigationBarBackgroundColor":"#5b95ff",
|
||||
// "navigationBarTextStyle": "white"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/info",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "个人信息"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "uview-ui/components/u-avatar-cropper/u-avatar-cropper",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "头像裁剪",
|
||||
// "navigationBarBackgroundColor": "#000000"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/help",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "帮助中心"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/pwd",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "修改密码"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/setting",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "系统设置"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/comment",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "意见反馈"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/about",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "关于我们"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/testData/form",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "新增编辑"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/testData/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "增删改查"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/common/webview",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "浏览网页"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/login/code",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "验证码"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/login/registerCode",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "验证码"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/service",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "联系客服"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/problem",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "常见问题"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/currency",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "通用"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/clear-cache",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "清除缓存"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/workbench/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "工作台"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/book/index",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "通讯录"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/book/personal-details",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "详情"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/msg/list-item",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "列表"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/workbench/add-form",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "请假申请"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/msg/examine-item",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "网上报销"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/msg/details",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "详情"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/user/modify",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "修改"
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// "path": "pages/sys/workbench/install",
|
||||
// "style": {
|
||||
// "navigationBarTitleText": "常用设置",
|
||||
// "navigationStyle": "custom" // 隐藏系统导航栏
|
||||
// }
|
||||
// }
|
||||
|
||||
// ],
|
||||
// "tabBar": {
|
||||
// "color": "#333333",
|
||||
// "selectedColor": "#4094ff",
|
||||
// "backgroundColor": "#ffffff",
|
||||
// "borderStyle": "white",
|
||||
// "list": [
|
||||
// {
|
||||
// "pagePath": "pages/sys/msg/index",
|
||||
// "iconPath": "static/aidex/tabbar/msg_1.png",
|
||||
// "selectedIconPath": "static/aidex/tabbar/msg_2.png",
|
||||
// "text": "消息"
|
||||
// },
|
||||
// // {
|
||||
// // "pagePath": "pages/sys/home/index",
|
||||
// // "iconPath": "static/aidex/tabbar/home_1.png",
|
||||
// // "selectedIconPath": "static/aidex/tabbar/home_2.png",
|
||||
// // "text": "首页"
|
||||
// // },
|
||||
// {
|
||||
// "pagePath": "pages/sys/workbench/index",
|
||||
// "iconPath": "static/aidex/tabbar/apply_1.png",
|
||||
// "selectedIconPath": "static/aidex/tabbar/apply_2.png",
|
||||
// "text": "工作台"
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/sys/book/index",
|
||||
// "iconPath": "static/aidex/tabbar/book_1.png",
|
||||
// "selectedIconPath": "static/aidex/tabbar/book_2.png",
|
||||
// "text": "通讯录"
|
||||
// },
|
||||
// {
|
||||
// "pagePath": "pages/sys/user/index",
|
||||
// "iconPath": "static/aidex/tabbar/my_1.png",
|
||||
// "selectedIconPath": "static/aidex/tabbar/my_2.png",
|
||||
// "text": "我的"
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
"pages":[
|
||||
{
|
||||
"path": "pages/sys/user/index",
|
||||
"path": "pages/sys/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationBarBackgroundColor":"#5b95ff",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "uview-ui/components/u-avatar-cropper/u-avatar-cropper",
|
||||
"style": {
|
||||
"navigationBarTitleText": "头像裁剪",
|
||||
"navigationBarBackgroundColor": "#000000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/help",
|
||||
"style": {
|
||||
"navigationBarTitleText": "帮助中心"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/pwd",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改密码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/setting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/comment",
|
||||
"style": {
|
||||
"navigationBarTitleText": "意见反馈"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/about",
|
||||
"style": {
|
||||
"navigationBarTitleText": "关于我们"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testData/form",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增编辑"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/testData/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "增删改查"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/common/webview",
|
||||
"style": {
|
||||
"navigationBarTitleText": "浏览网页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/login/code",
|
||||
"style": {
|
||||
"navigationBarTitleText": "验证码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/login/registerCode",
|
||||
"style": {
|
||||
"navigationBarTitleText": "验证码"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/service",
|
||||
"style": {
|
||||
"navigationBarTitleText": "联系客服"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/problem",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常见问题"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/currency",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通用"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/clear-cache",
|
||||
"style": {
|
||||
"navigationBarTitleText": "清除缓存"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/workbench/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作台"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/book/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "通讯录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/book/personal-details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/msg/list-item",
|
||||
"style": {
|
||||
"navigationBarTitleText": "列表"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/workbench/add-form",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/msg/examine-item",
|
||||
"style": {
|
||||
"navigationBarTitleText": "网上报销"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/msg/details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/modify",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/workbench/install",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常用设置",
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationStyle": "custom" // 隐藏系统导航栏
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path": "pages/sys/home/home",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/workbench/workbench",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/mine",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/changeInfo/changeInfo",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/message/message",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/serviceCenter/serviceCenter",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务中心"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/serviceCenter/questionDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务中心"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/myVisitor/myVisitor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的访客"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/myVisitor/creatVisitor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "发起邀约"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/sys/user/myVisitor/visitorInfo",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myPayment/myPayment",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "停车缴费"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myPayment/paymentRecords",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "缴费记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myRepair/myRepair",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "报事报修"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myRepair/addRepair",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "新增"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myRepair/repaired",
|
||||
"style" :
|
||||
{
|
||||
"navigationStyle" : "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myRepair/repairEvaluate",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText": "服务评价"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/user/myRecord/myRecord",
|
||||
"style" :
|
||||
{
|
||||
"navigationStyle" : "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "pages/sys/workbench/oa/oa",
|
||||
"style" :
|
||||
{
|
||||
"navigationStyle" : "custom"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"path" : "pages/sys/workbench/oa/oaDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationStyle" : "custom"
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
"tabBar": {
|
||||
"color": "#232323",
|
||||
"selectedColor": "#0652FF",
|
||||
"backgroundColor": "#fff",
|
||||
"borderStyle": "black",
|
||||
"list": [{
|
||||
"pagePath": "pages/sys/home/home",
|
||||
"iconPath": "static/ic_main_home.png",
|
||||
"selectedIconPath": "static/ic_main_home_selected.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/sys/workbench/workbench",
|
||||
"iconPath": "static/ic_main_work.png",
|
||||
"selectedIconPath": "static/ic_main_work_selected.png",
|
||||
"text": "工作台"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/sys/user/mine",
|
||||
"iconPath": "static/ic_main_mine.png",
|
||||
"selectedIconPath": "/static/ic_main_mine_selected.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"subPackages": [
|
||||
|
||||
],
|
||||
@@ -213,43 +411,5 @@
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "Aidex",
|
||||
"navigationBarBackgroundColor": "#ffffff"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#333333",
|
||||
"selectedColor": "#4094ff",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "white",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/sys/msg/index",
|
||||
"iconPath": "static/aidex/tabbar/msg_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/msg_2.png",
|
||||
"text": "消息"
|
||||
},
|
||||
// {
|
||||
// "pagePath": "pages/sys/home/index",
|
||||
// "iconPath": "static/aidex/tabbar/home_1.png",
|
||||
// "selectedIconPath": "static/aidex/tabbar/home_2.png",
|
||||
// "text": "首页"
|
||||
// },
|
||||
{
|
||||
"pagePath": "pages/sys/workbench/index",
|
||||
"iconPath": "static/aidex/tabbar/apply_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/apply_2.png",
|
||||
"text": "工作台"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/sys/book/index",
|
||||
"iconPath": "static/aidex/tabbar/book_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/book_2.png",
|
||||
"text": "通讯录"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/sys/user/index",
|
||||
"iconPath": "static/aidex/tabbar/my_1.png",
|
||||
"selectedIconPath": "static/aidex/tabbar/my_2.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
409
pages/sys/home/home.vue
Normal file
@@ -0,0 +1,409 @@
|
||||
<template>
|
||||
<view class="home-container">
|
||||
<!-- 顶部Banner区域,包含所有顶部内容 -->
|
||||
<view class="home-header">
|
||||
<swiper class="banner-swiper" :current="current" @change="onBannerChange" :autoplay="true" :interval="3000" :circular="true">
|
||||
<swiper-item v-for="(item, idx) in banners" :key="idx">
|
||||
<image :src="item.img" class="banner-bg-img" mode="aspectFill" />
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<!-- 自定义指示器 -->
|
||||
<view class="banner-indicator">
|
||||
<view v-for="(item, idx) in banners" :key="idx" :class="['banner-dot', current === idx ? 'active' : '']"></view>
|
||||
</view>
|
||||
<view class="home-top">
|
||||
<image class="icon3" src="/static/ic_tq.png" />
|
||||
<text class="weather">21-36℃</text>
|
||||
<view class="search-bar">
|
||||
<image src="/static/ic_search.png" class="search-icon-img" />
|
||||
<input class="search-input" placeholder="搜索" />
|
||||
</view>
|
||||
<view class="top-icons">
|
||||
<image class="icon1" src="/static/ic_scan.png" />
|
||||
<image class="icon2" src="/static/ic_msg.png" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 白色圆角虚线面板 -->
|
||||
<view class="main-panel">
|
||||
<!-- 九宫格功能区 -->
|
||||
<view class="grid-area">
|
||||
<view class="grid-item" v-for="(item, idx) in gridList" :key="idx">
|
||||
<image :src="item.icon" class="grid-icon" />
|
||||
<text class="grid-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 滚动资讯条 -->
|
||||
<view class="news-bar">
|
||||
<text class="news-label">头条</text>
|
||||
<scroll-view scroll-x class="news-scroll">
|
||||
<text v-for="(item, idx) in newsList" :key="idx" class="news-item">{{ item }}</text>
|
||||
</scroll-view>
|
||||
<text class="news-arrow">›</text>
|
||||
</view>
|
||||
<!-- 热门活动区 -->
|
||||
<view class="hot-section">
|
||||
<view class="hot-title-row">
|
||||
<text class="hot-title">热门活动</text>
|
||||
<text class="hot-more">全部热门活动 ></text>
|
||||
</view>
|
||||
<view class="hot-list">
|
||||
<view class="hot-card" v-for="(item, idx) in hotList" :key="idx">
|
||||
<image :src="item.img" class="hot-img" mode="aspectFill" />
|
||||
<view class="hot-info">
|
||||
<text class="hot-tag">#热门活动</text>
|
||||
<text class="hot-desc">{{ item.title }}</text>
|
||||
<view class="hot-meta">
|
||||
<text class="hot-date">{{ item.date }}</text>
|
||||
<text class="hot-status">进行中</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Home',
|
||||
data() {
|
||||
return {
|
||||
banners: [{
|
||||
img: 'https://picsum.photos/750/300?random=1'
|
||||
},
|
||||
{
|
||||
img: 'https://picsum.photos/750/300?random=2'
|
||||
}
|
||||
],
|
||||
current: 0,
|
||||
gridList: [{
|
||||
icon: 'https://picsum.photos/80/80?random=3',
|
||||
text: '报事报修'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=4',
|
||||
text: '停车缴费'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=5',
|
||||
text: '生活服务'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=6',
|
||||
text: '服务中心'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=7',
|
||||
text: '会议预约'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=8',
|
||||
text: '工单管理'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=9',
|
||||
text: '访客管理'
|
||||
},
|
||||
{
|
||||
icon: 'https://picsum.photos/80/80?random=10',
|
||||
text: '敬请期待'
|
||||
}
|
||||
],
|
||||
newsList: [
|
||||
'数智南川|最新资讯1',
|
||||
'数智南川|最新资讯2',
|
||||
'数智南川|最新资讯3'
|
||||
],
|
||||
hotList: [{
|
||||
img: 'https://picsum.photos/700/280?random=13',
|
||||
title: '世界骑行日 低碳出行 让城市更美好',
|
||||
date: '2025-07-03'
|
||||
},
|
||||
{
|
||||
img: 'https://picsum.photos/700/280?random=14',
|
||||
title: '仲夏之夜低碳出行·绿色生活让城市更美好',
|
||||
date: '2025-07-03'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onBannerChange(e) {
|
||||
this.current = e.detail.current;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background: #f8f8f8;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.home-header {
|
||||
position: relative;
|
||||
height: 446rpx;
|
||||
width: 100vw;
|
||||
margin-bottom: -40rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.banner-swiper {
|
||||
width: 100vw;
|
||||
height: 446rpx;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
.banner-bg-img {
|
||||
width: 100vw;
|
||||
height: 446rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
.banner-indicator {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 64rpx;
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
z-index: 2;
|
||||
}
|
||||
.banner-dot {
|
||||
width: 14rpx;
|
||||
height: 14rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.6);
|
||||
margin: 0 8rpx;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.banner-dot.active {
|
||||
background: #3B7BFF;
|
||||
}
|
||||
.home-top {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
padding: 80rpx 20rpx 0 20rpx;
|
||||
}
|
||||
.weather {
|
||||
font-size: 24rpx;
|
||||
margin-left: 10rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
.search-bar {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 30rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 56rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
.search-input::placeholder {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
.search-icon-img {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
.search-input {
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 26rpx;
|
||||
flex: 1;
|
||||
color: #fff;
|
||||
}
|
||||
.top-icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.icon1 {
|
||||
width: 33rpx;
|
||||
height: 33rpx;
|
||||
margin-left: 19rpx;
|
||||
}
|
||||
.icon2 {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
margin-left: 23rpx;
|
||||
}
|
||||
.icon3 {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.main-panel {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.grid-area {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20rpx 0 10rpx 0;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.grid-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.grid-text {
|
||||
font-size: 24rpx;
|
||||
color: #1D1D1D;
|
||||
}
|
||||
|
||||
.news-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10rpx 0;
|
||||
border-top: 1rpx solid #f5f5f5;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.news-label {
|
||||
color: #FF6A00;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
margin-right: 16rpx;
|
||||
border: 1rpx solid #FF6A00;
|
||||
border-radius: 4rpx;
|
||||
padding: 2rpx 6rpx;
|
||||
}
|
||||
|
||||
.news-scroll {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.news-item {
|
||||
display: inline-block;
|
||||
margin-right: 30rpx;
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.news-arrow {
|
||||
color: #999;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.hot-section {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.hot-title-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.hot-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
position: relative;
|
||||
padding-left: 16rpx;
|
||||
}
|
||||
.hot-title::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 6rpx;
|
||||
height: 30rpx;
|
||||
background: #3B7BFF;
|
||||
border-radius: 3rpx;
|
||||
}
|
||||
|
||||
.hot-more {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.hot-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.hot-card {
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.hot-img {
|
||||
width: 100%;
|
||||
height: 280rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.hot-info {
|
||||
padding: 16rpx 20rpx 20rpx 20rpx;
|
||||
}
|
||||
|
||||
.hot-tag {
|
||||
color: #3B7BFF;
|
||||
font-size: 22rpx;
|
||||
margin-bottom: 6rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hot-desc {
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
margin-bottom: 10rpx;
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.hot-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hot-date {
|
||||
color: #999;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.hot-status {
|
||||
color: #fff;
|
||||
background: #3B7BFF;
|
||||
font-size: 22rpx;
|
||||
border-radius: 8rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
}
|
||||
</style>
|
266
pages/sys/login/login.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<template>
|
||||
<view class="login-container">
|
||||
<!-- 顶部渐变背景和标题 -->
|
||||
<view class="login-header">
|
||||
<image class="login-bg-img" src="/static/ic_login_topbg.png" mode="widthFix" />
|
||||
<view class="login-title">登录注册</view>
|
||||
<view class="login-subtitle">欢迎使用数智南川</view>
|
||||
</view>
|
||||
<!-- 表单区域 -->
|
||||
<view class="login-form">
|
||||
<view class="input-row">
|
||||
<image class="iconfont" src="/static/ic_login_phone.png" />
|
||||
<input class="login-input" type="text" placeholder="输入手机号" v-model="username" />
|
||||
</view>
|
||||
<view class="input-row">
|
||||
<image class="iconfont2" src="/static/ic_login_code.png" />
|
||||
<input class="login-input" type="text" placeholder="请输入验证码" />
|
||||
<button class="code-btn">获取校验码</button>
|
||||
</view>
|
||||
<view class="protocol-row">
|
||||
<label class="custom-checkbox-label">
|
||||
<input type="checkbox" :checked="checked" @change="handleCheckboxChange"
|
||||
class="custom-checkbox-input" />
|
||||
<image :src="checked ? '/static/ic_login_agree.png' : '/static/ic_login_dis.png'"
|
||||
class="custom-checkbox-img" @click="handleCheckboxChange({ target: { checked: !checked }})" />
|
||||
</label>
|
||||
<text>同意</text>
|
||||
<text class="protocol-link">《用户协议》</text>
|
||||
<text>和</text>
|
||||
<text class="protocol-link">《隐私政策》</text>
|
||||
</view>
|
||||
<button class="login-btn" @click="submit">登录</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import base64 from '@/common/base64.js';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
phoneNo: '',
|
||||
username: 'admin',
|
||||
password: 'admin123',
|
||||
loginType: 'currentPhone',
|
||||
showPassword: false,
|
||||
remember: true,
|
||||
isValidCodeLogin: false,
|
||||
validCode: '',
|
||||
imgValidCodeSrc: null,
|
||||
list: [{
|
||||
name: '用户名'
|
||||
}, {
|
||||
name: '手机号'
|
||||
}],
|
||||
current: 0,
|
||||
activeColor: '#007aff',
|
||||
checked: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit() {
|
||||
if (this.username.length == 0) {
|
||||
this.$u.toast('请输入账号');
|
||||
return;
|
||||
}
|
||||
if (this.password.length == 0) {
|
||||
this.$u.toast('请输入密码');
|
||||
return;
|
||||
}
|
||||
let res = await this.$u.api.login({
|
||||
"tenantId": "000000", // 把单引号换成双引号
|
||||
"username": this.username,
|
||||
"password": this.password,
|
||||
"grantType": "password",
|
||||
"uuid": "7cb3ea4fe2ae4f08bbd561c94ef0191b",
|
||||
"clientId": "dab457a1ea14411787c240db05bb0832"
|
||||
});
|
||||
console.log(res)
|
||||
if (res.code == "200") {
|
||||
this.$u.toast("登录成功")
|
||||
this.$store.commit('$uStore', {
|
||||
name: 'vuex_token',
|
||||
value: res.data.access_token
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/sys/home/home'
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
|
||||
handleCheckboxChange(e) {
|
||||
this.checked = e.target.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-container {
|
||||
min-height: 100vh;
|
||||
background: #fafbfc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.login-bg-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.login-title,
|
||||
.login-subtitle {
|
||||
position: relative;
|
||||
top: 164rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
color: #fff;
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.login-subtitle {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
width: 80%;
|
||||
margin-top: 400rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
width: 27rpx;
|
||||
height: 43rpx;
|
||||
}
|
||||
|
||||
.iconfont2 {
|
||||
font-size: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
width: 31rpx;
|
||||
height: 35rpx;
|
||||
}
|
||||
|
||||
.login-input {
|
||||
flex: 1;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 28rpx;
|
||||
padding: 10rpx 0;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.code-btn {
|
||||
background: none;
|
||||
color: #2e6cf6;
|
||||
border: none;
|
||||
font-size: 26rpx;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
|
||||
.protocol-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20rpx 0 40rpx 0;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.protocol-checkbox {
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.protocol-link {
|
||||
color: #2e6cf6;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, #2e6cf6 0%, #4fc3f7 100%);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin-top: 268rpx;
|
||||
}
|
||||
|
||||
.custom-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.custom-checkbox-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.custom-checkbox-span {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #2e6cf6;
|
||||
background: #fff;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.custom-checkbox-span.checked {
|
||||
background: #2e6cf6;
|
||||
border-color: #2e6cf6;
|
||||
}
|
||||
|
||||
.custom-checkbox-span.checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 7rpx;
|
||||
top: 7rpx;
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.custom-checkbox-img {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
</style>
|
@@ -70,7 +70,7 @@ page {
|
||||
overflow: hidden;
|
||||
font-size: 30rpx;
|
||||
line-height: 50rpx;
|
||||
/deep/ p {
|
||||
::v-deep p {
|
||||
margin-bottom: 20rpx;
|
||||
text-indent: 60rpx;
|
||||
}
|
||||
|
236
pages/sys/user/changeInfo/changeInfo.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<view class="change-info-container">
|
||||
<image src="/static/ic_back.png" class="back-arrow" @click="goBack"/>
|
||||
<view class="title-main">完善你的资料</view>
|
||||
<view class="title-sub">让大家更好地了解你</view>
|
||||
<view class="avatar-section">
|
||||
<image class="avatar-img" src="/static/avatar.png" />
|
||||
<view class="avatar-camera">
|
||||
<image src="/static/ic_camera.png" class="camera-icon" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-section">
|
||||
<view class="form-label">取个昵称</view>
|
||||
<view class="input-row">
|
||||
<input class="form-input" v-model="nickname" placeholder="请输入昵称" />
|
||||
<view class="input-suffix">
|
||||
<image src="/static/ic_i_c_01.png" class="random-icon" />
|
||||
<text class="random-text">随机</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-label">你的手机号</view>
|
||||
<view class="input-row">
|
||||
<input class="form-input" v-model="phone" placeholder="请输入您的手机号" />
|
||||
<image src="/static/ic_arrow_right.png" class="arrow-icon" />
|
||||
</view>
|
||||
<view class="form-label">你的性别(不可修改)</view>
|
||||
<view class="gender-row">
|
||||
<view class="gender-item selected">
|
||||
<image src="/static/ic_i_c_02.png" class="gender-icon" />
|
||||
</view>
|
||||
<view class="gender-item">
|
||||
<image src="/static/ic_i_c_03.png" class="gender-icon" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-row"><text class="info-label">部门</text>生活服务部</view>
|
||||
<view class="info-row"><text class="info-label">岗位</text>客服</view>
|
||||
<view class="info-row"><text class="info-label">工号</text>A10235</view>
|
||||
</view>
|
||||
<button class="submit-btn">确认修改</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
nickname: '帅气的小南瓜',
|
||||
phone: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.change-info-container {
|
||||
position: relative;
|
||||
padding-bottom: 60rpx;
|
||||
padding-top: 118rpx;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(180deg, #d2edff 0%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.back-arrow {
|
||||
width: 24rpx;
|
||||
height: 42rpx;
|
||||
left: 45rpx;
|
||||
}
|
||||
|
||||
.title-main {
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
margin-top: 45rpx;
|
||||
margin-left: 65rpx;
|
||||
}
|
||||
|
||||
.title-sub {
|
||||
font-size: 50rpx;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
margin-left: 65rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-left: 68rpx;
|
||||
margin-bottom: 62rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.avatar-camera {
|
||||
position: absolute;
|
||||
left: 100rpx;
|
||||
top: 90rpx;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
background: #bbb;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.camera-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin: 0 68rpx;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
color: #737373;
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 17rpx;
|
||||
margin-top: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 14rpx;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
margin-bottom: 18rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 98rpx;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
border: none;
|
||||
font-weight: bold;
|
||||
font-size: 33rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.input-suffix {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.random-icon {
|
||||
width: 31rpx;
|
||||
height: 27rpx;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
|
||||
.random-text {
|
||||
color: #636363;
|
||||
font-size: 25rpx;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.gender-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 50rpx;
|
||||
padding-top: 15rpx;
|
||||
}
|
||||
|
||||
.gender-item {
|
||||
width: 188rpx;
|
||||
height: 97rpx;
|
||||
border: 2rpx dashed #bbb;
|
||||
border-radius: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 24rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.gender-item.selected {
|
||||
background: #e0e0e0;
|
||||
border-color: #bbb;
|
||||
}
|
||||
|
||||
.gender-icon {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #737373;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #737373;
|
||||
width: 134rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 90vw;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, #2e6cf6 0%, #4fc3f7 100%);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin: 80rpx auto 40rpx auto;
|
||||
display: block;
|
||||
box-shadow: 0 8rpx 24rpx rgba(46, 108, 246, 0.12);
|
||||
}
|
||||
</style>
|
@@ -39,7 +39,7 @@ page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
/deep/ .u-cell-title {
|
||||
::v-deep .u-cell-title {
|
||||
padding: 25rpx 30rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
@@ -77,7 +77,7 @@ page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
/deep/ .u-cell-title {
|
||||
::v-deep .u-cell-title {
|
||||
padding: 25rpx 30rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
164
pages/sys/user/message/message.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<view class="msg-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="msg-navbar">
|
||||
<image src="/static/ic_msg_01.png" class="msg-navbar-bg" mode="aspectFill" />
|
||||
<image src="/static/ic_back_white.webp" class="msg-back" @click="goBack" />
|
||||
<text class="msg-title">消息中心</text>
|
||||
</view>
|
||||
<!-- 可滚动内容区 -->
|
||||
<view class="msg-scroll-content">
|
||||
<!-- 消息列表 -->
|
||||
<view v-if="msgList.length" class="msg-list">
|
||||
<view class="msg-item" v-for="(item, idx) in msgList" :key="idx">
|
||||
<image :src="item.icon" class="msg-icon" />
|
||||
<view class="msg-content">
|
||||
<view class="msg-row">
|
||||
<text class="msg-main-title">{{ item.title }}</text>
|
||||
<text class="msg-time">{{ item.time }}</text>
|
||||
</view>
|
||||
<view class="msg-desc">{{ item.desc }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 空状态 -->
|
||||
<view v-else class="msg-empty">
|
||||
<image src="/static/ic_msg_empty.png" class="msg-empty-img" />
|
||||
<text class="msg-empty-text">暂无更多消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
msgList: [
|
||||
{
|
||||
icon: '/static/ic_msg_sys.png',
|
||||
title: '系统消息',
|
||||
desc: '欢迎注册!更多好礼等你来....',
|
||||
time: '12:20'
|
||||
},
|
||||
{
|
||||
icon: '/static/ic_msg_feedback.png',
|
||||
title: '反馈进度',
|
||||
desc: '查看更多反馈进度....',
|
||||
time: '12:20'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.msg-container {
|
||||
height: 100vh;
|
||||
background: #F0F3FF;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.msg-navbar {
|
||||
width: 100%;
|
||||
height: 142rpx;
|
||||
position: relative;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.msg-navbar-bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 142rpx;
|
||||
z-index: 0;
|
||||
}
|
||||
.msg-back {
|
||||
position: absolute;
|
||||
left: 32rpx;
|
||||
width: 20rpx;
|
||||
height: 36rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.msg-title {
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.msg-scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.msg-list {
|
||||
background: #fff;
|
||||
margin: 0 0 0 0;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
.msg-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx;
|
||||
border-bottom: 1px solid #f7f7f7;
|
||||
}
|
||||
.msg-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.msg-icon {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
margin-right: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
.msg-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.msg-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.msg-main-title {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
.msg-time {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
.msg-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 12rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.msg-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 120rpx;
|
||||
}
|
||||
.msg-empty-img {
|
||||
width: 320rpx;
|
||||
height: 220rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.msg-empty-text {
|
||||
color: #bbb;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
232
pages/sys/user/mine.vue
Normal file
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<view class="mine-container">
|
||||
<!-- 顶部蓝色背景和个人信息 -->
|
||||
<view class="mine-header">
|
||||
<image class="mine-bg" src="/static/ic_mine_topbg.png" mode="widthFix" />
|
||||
<view class="mine-info-row">
|
||||
<image class="mine-avatar" src="/static/ic_mine_head.png" />
|
||||
<view class="mine-userinfo">
|
||||
<view class="mine-nick">昵称</view>
|
||||
<view class="mine-phone">1789548878</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mine-header-icons">
|
||||
<image class="mine-header-icon" src="/static/ic_mine_notice.png" @click="handleItemClick(-1)"/>
|
||||
<image class="mine-header-icon2" src="/static/ic_mine_setting.png" @click="handleItemClick(-2)"/>
|
||||
</view>
|
||||
<view class="mine-header-wave"></view>
|
||||
</view>
|
||||
<!-- 白色圆角面板 -->
|
||||
<view class="mine-panel">
|
||||
<view class="mine-list">
|
||||
<view class="mine-list-item" v-for="(item, idx) in list" :key="idx" @click="handleItemClick(idx)">
|
||||
<image class="mine-list-icon" :src="item.icon" />
|
||||
<text class="mine-list-text">{{ item.text }}</text>
|
||||
<text v-if="item.extra" class="mine-list-extra">{{ item.extra }}</text>
|
||||
<image v-if="!item.extra" class="mine-list-arrow" src="/static/ic_arrow_gray.webp" />
|
||||
</view>
|
||||
</view>
|
||||
<button class="logout-btn">退出登录</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Mine',
|
||||
data() {
|
||||
return {
|
||||
list: [
|
||||
{ icon: '/static/ic_mine_info.png', text: '我的信息' },
|
||||
{ icon: '/static/ic_mine_pay.png', text: '我的缴费' },
|
||||
{ icon: '/static/ic_mine_repair.png', text: '我的报修' },
|
||||
{ icon: '/static/ic_mine_visitor.png', text: '我的访客' },
|
||||
{ icon: '/static/ic_mine_check.png', text: '我的考勤' },
|
||||
{ icon: '/static/ic_mine_pwd.png', text: '修改密码' },
|
||||
{ icon: '/static/ic_mine_version.png', text: '系统版本', extra: 'v1.00.01' },
|
||||
{ icon: '/static/ic_mine_setting2.png', text: '设置' }
|
||||
]
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.$u.api.getUserInfo().then(res => {
|
||||
if (res.code == '200'){
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
handleItemClick(idx) {
|
||||
if (idx === 0) {
|
||||
uni.navigateTo({ url: '/pages/sys/user/changeInfo/changeInfo' });
|
||||
}else if(idx === -1){
|
||||
uni.navigateTo({ url: '/pages/sys/user/message/message' });
|
||||
}else if(idx === -2){
|
||||
uni.navigateTo({ url: '/pages/sys/user/serviceCenter/serviceCenter' });
|
||||
}else if(idx === 1){
|
||||
uni.navigateTo({ url: '/pages/sys/user/myPayment/myPayment' });
|
||||
}else if(idx === 2){
|
||||
uni.navigateTo({ url: '/pages/sys/user/myRepair/myRepair' });
|
||||
}else if(idx === 3){
|
||||
uni.navigateTo({ url: '/pages/sys/user/myVisitor/myVisitor' });
|
||||
}else if(idx === 4){
|
||||
uni.navigateTo({ url: '/pages/sys/user/myRecord/myRecord' });
|
||||
// uni.navigateTo({ url: '/pages/workbench/oa/oa' });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mine-container {
|
||||
height: 100vh;
|
||||
background: #f8f8f8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.mine-header {
|
||||
width: 100%;
|
||||
height: 343rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding-bottom: 0;
|
||||
flex-shrink: 0; /* 防止被压缩 */
|
||||
}
|
||||
.mine-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 343rpx;
|
||||
z-index: 0;
|
||||
}
|
||||
.mine-header-wave {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -18rpx;
|
||||
width: 100%;
|
||||
height: 36rpx;
|
||||
background: #fff;
|
||||
border-bottom-left-radius: 36rpx;
|
||||
border-bottom-right-radius: 36rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
.mine-info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
margin-left: 32rpx;
|
||||
bottom: 127rpx;
|
||||
}
|
||||
.mine-header-icons {
|
||||
position: absolute;
|
||||
right: 22rpx;
|
||||
top: 86rpx;
|
||||
display: flex;
|
||||
z-index: 4;
|
||||
}
|
||||
.mine-avatar {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
margin-right: 24rpx;
|
||||
border: 4rpx solid #fff;
|
||||
}
|
||||
.mine-userinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.mine-nick {
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
.mine-phone {
|
||||
color: #fff;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.mine-header-icon {
|
||||
width: 30rpx;
|
||||
height: 35rpx;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
.mine-header-icon2 {
|
||||
width: 33rpx;
|
||||
height: 33rpx;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
.mine-panel {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
border-top-left-radius: 30rpx;
|
||||
border-top-right-radius: 30rpx;
|
||||
margin-top: -51rpx;
|
||||
box-shadow: 0 -2rpx 16rpx rgba(0,0,0,0.04);
|
||||
padding: 0 0 40rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1; /* 占据剩余空间 */
|
||||
overflow-y: auto; /* 开启滚动 */
|
||||
}
|
||||
.mine-list {
|
||||
width: 92vw;
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
margin: 51rpx auto;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
}
|
||||
.mine-list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0 0 0;
|
||||
height: 96rpx;
|
||||
position: relative;
|
||||
background: transparent;
|
||||
}
|
||||
.mine-list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.mine-list-icon {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
margin: 0 24rpx 0 30rpx;
|
||||
}
|
||||
.mine-list-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
.mine-list-extra {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.mine-list-arrow {
|
||||
width: 18rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
.logout-btn {
|
||||
width: 88vw;
|
||||
height: 80rpx;
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin: 100rpx auto 0 auto;
|
||||
display: block;
|
||||
box-shadow: 0 18rpx 24rpx rgba(0,0,0,0.18);
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
537
pages/sys/user/myPayment/myPayment.vue
Normal file
@@ -0,0 +1,537 @@
|
||||
<template>
|
||||
<view class="page-wrapper">
|
||||
<!-- 顶部title栏 -->
|
||||
<view class="pay-container">
|
||||
<!-- 未绑定车牌状态 -->
|
||||
<view v-if="status === 'unbound'" class="pay-unbound">
|
||||
<image src="/static/ic_my_payment_01.png" class="pay-empty-img" />
|
||||
<view class="pay-unbound-tip">你还未绑定车牌哦~</view>
|
||||
<view class="pay-unbound-link" @click="showBindDialog = true">现在去绑定</view>
|
||||
</view>
|
||||
<!-- 已绑定车牌状态 -->
|
||||
<view v-else class="pay-binded">
|
||||
<view class="pay-car-card">
|
||||
<view class="pay-car-row">
|
||||
<image src="/static/ic_my_payment_02.png" class="pay-car-icon" />
|
||||
<view class="pay-car-num">{{ carInfo.number }}</view>
|
||||
<view class="pay-car-status">{{ carInfo.status }}</view>
|
||||
</view>
|
||||
<view class="pay-car-addr">{{ carInfo.addr }}</view>
|
||||
<view class="pay-car-info">
|
||||
<view class="pay-car-time">
|
||||
<view>停放时长</view>
|
||||
<view class="pay-car-info-val">{{ carInfo.duration }}</view>
|
||||
</view>
|
||||
<view class="pay-car-fee">
|
||||
<view>预计费用</view>
|
||||
<view class="pay-car-fee-val">¥{{ carInfo.fee }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<button class="pay-car-btn">立即缴费</button>
|
||||
</view>
|
||||
<view class="pay-list-entry">
|
||||
<view class="pay-list-item">缴费标准
|
||||
<image class="mine-list-arrow" src="/static/ic_arrow_gray.webp" />
|
||||
</view>
|
||||
<view class="pay-list-item" @click="goToRecords">缴费记录
|
||||
<image class="mine-list-arrow" src="/static/ic_arrow_gray.webp"/>
|
||||
</view>
|
||||
</view>
|
||||
<button class="pay-add-btn">新增停车</button>
|
||||
</view>
|
||||
<!-- 绑定车牌弹窗 -->
|
||||
<view v-if="showBindDialog" class="pay-dialog-mask" @click.self="showBindDialog = false">
|
||||
<view class="pay-dialog-box">
|
||||
<view class="pay-dialog-title-row">
|
||||
<view class="pay-dialog-title">输入车牌号</view>
|
||||
<image src="/static/ic_close_01.png" class="pay-dialog-close" @click="showBindDialog = false" />
|
||||
</view>
|
||||
<view class="pay-dialog-input-row">
|
||||
<!-- 省份简称输入框 -->
|
||||
<input class="pay-dialog-input province-input" :value="carNumArr[0]" readonly
|
||||
:focus="focusIndex === -1" @click="showProvinceKeyboard = true; focusIndex = -1" />
|
||||
<!-- 后6位 -->
|
||||
<input v-for="(item, idx) in 6" :key="idx" maxlength="1" class="pay-dialog-input"
|
||||
v-model="carNumArr[idx+1]" :focus="focusIndex === idx" @input="onCarInput($event, idx)"
|
||||
@keydown.native="onCarKeydown($event, idx)" @paste="onCarPaste($event)" />
|
||||
</view>
|
||||
<button class="pay-dialog-btn" @click="bindCar">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 省份简称自定义键盘弹窗 -->
|
||||
<view v-if="showProvinceKeyboard" class="province-keyboard-mask" @click.self="showProvinceKeyboard = false">
|
||||
<view class="province-keyboard-box">
|
||||
<view class="province-keyboard-title">选择省份简称</view>
|
||||
<view class="province-keyboard-grid">
|
||||
<view v-for="(item, idx) in provinceList" :key="idx" class="province-keyboard-btn"
|
||||
@click="selectProvince(item)">{{ item }}</view>
|
||||
</view>
|
||||
<button class="province-keyboard-cancel" @click="showProvinceKeyboard = false">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
status: 'unbound', // unbound, binded
|
||||
showBindDialog: false,
|
||||
carNumArr: ['渝', '', '', '', '', '', ''],
|
||||
showProvinceKeyboard: false,
|
||||
focusIndex: 0,
|
||||
isBackspace: false,
|
||||
// 假数据
|
||||
carInfo: {
|
||||
number: '渝A-65891',
|
||||
status: '停放中',
|
||||
addr: '服务中心1栋A区五层-018号',
|
||||
duration: '01:25:33',
|
||||
fee: 12
|
||||
},
|
||||
provinceList: [
|
||||
'京', '津', '沪', '渝', '冀', '豫', '云', '辽', '黑', '湘',
|
||||
'皖', '鲁', '新', '苏', '浙', '赣', '鄂', '桂', '甘', '晋',
|
||||
'蒙', '陕', '吉', '闽', '贵', '粤', '青', '藏', '川', '宁', '琼'
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
bindCar() {
|
||||
this.showBindDialog = false;
|
||||
this.status = 'binded';
|
||||
},
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
onCarInput(e, idx) {
|
||||
let val = e.detail.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
|
||||
this.$set(this.carNumArr, idx + 1, val);
|
||||
// 只在输入时自动跳到下一个,避免键盘频繁弹出
|
||||
if (val && idx < 5) {
|
||||
this.focusIndex = idx + 1;
|
||||
}
|
||||
},
|
||||
onCarKeydown(e, idx) {
|
||||
// 记录是否是删除键,但删除时不自动回退聚焦
|
||||
this.isBackspace = (e.key === 'Backspace' || e.keyCode === 8);
|
||||
},
|
||||
onCarPaste(e) {
|
||||
let paste = (e.clipboardData || window.clipboardData).getData('text').toUpperCase().replace(/[^A-Z0-9]/g,
|
||||
'');
|
||||
if (paste.length > 0) {
|
||||
for (let i = 0; i < 6; i++) {
|
||||
this.$set(this.carNumArr, i + 1, paste[i] || '');
|
||||
}
|
||||
this.focusIndex = 5;
|
||||
}
|
||||
e.preventDefault();
|
||||
},
|
||||
selectProvince(item) {
|
||||
this.$set(this.carNumArr, 0, item);
|
||||
this.showProvinceKeyboard = false;
|
||||
// 自动聚焦第二位
|
||||
this.focusIndex = 0;
|
||||
},
|
||||
goToRecords() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/sys/user/myPayment/paymentRecords'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrapper {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.pay-navbar {
|
||||
width: 100%;
|
||||
height: 160rpx;
|
||||
padding-top: 70rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pay-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.pay-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.pay-container {
|
||||
background: #F7F8FA;
|
||||
padding-bottom: 120rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pay-unbound {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 160rpx;
|
||||
}
|
||||
|
||||
.pay-empty-img {
|
||||
width: 320rpx;
|
||||
height: 180rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.pay-unbound-tip {
|
||||
font-size: 30rpx;
|
||||
color: #222;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.pay-unbound-link {
|
||||
color: #0090FF;
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.pay-binded {
|
||||
margin-top: 80rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pay-car-card {
|
||||
position: relative;
|
||||
width: 80vw;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
padding: 56rpx 40rpx 30rpx 40rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.pay-car-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 54rpx;
|
||||
}
|
||||
|
||||
.pay-car-icon {
|
||||
width: 43rpx;
|
||||
height: 35rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.pay-car-num {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #000;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.pay-car-status {
|
||||
font-size: 24rpx;
|
||||
color: #FEFEFE;
|
||||
background: linear-gradient(90deg, #05C58C 0%, #73FFC9 100%);
|
||||
border-radius: 12rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.pay-car-addr {
|
||||
position: absolute;
|
||||
top: 94rpx;
|
||||
left: 98rpx;
|
||||
font-size: 24rpx;
|
||||
color: #878787;
|
||||
}
|
||||
|
||||
.pay-car-info {
|
||||
position: relative;
|
||||
width: 70vw;
|
||||
height: 113rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 54rpx;
|
||||
background: #E9F4FF;
|
||||
border: 1rpx solid #2E93FF;
|
||||
border-radius: 10rpx;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.pay-car-time {
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
left: 33rpx;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pay-car-info-val {
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.pay-car-fee {
|
||||
position: absolute;
|
||||
top: 16rpx;
|
||||
right: 58rpx;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pay-car-fee-val {
|
||||
color: #F3831F;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.pay-car-btn {
|
||||
width: 283rpx;
|
||||
height: 57rpx;
|
||||
background: linear-gradient(90deg, #005DE9 0%, #4B9BFF 100%);
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
border-radius: 15rpx;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
/* 新增:flex居中 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pay-list-entry {
|
||||
width: 92vw;
|
||||
}
|
||||
|
||||
.pay-list-item {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
padding: 28rpx 32rpx;
|
||||
margin-bottom: 18rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.pay-list-arrow {
|
||||
color: #bbb;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.pay-add-btn {
|
||||
width: 90vw;
|
||||
height: 80rpx;
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 200rpx;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.pay-dialog-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pay-dialog-box {
|
||||
width: 70vw;
|
||||
background: #fff;
|
||||
border-radius: 28rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
|
||||
padding: 48rpx 36rpx 36rpx 36rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pay-dialog-title-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 80rpx;
|
||||
}
|
||||
|
||||
.pay-dialog-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.pay-dialog-close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.pay-dialog-input-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 80rpx;
|
||||
gap: 28rpx;
|
||||
}
|
||||
|
||||
.pay-dialog-input {
|
||||
width: 43rpx;
|
||||
height: 53rpx;
|
||||
background: #EEEEEE;
|
||||
border-radius: 5rpx;
|
||||
font-size: 32rpx;
|
||||
color: #222;
|
||||
text-align: center;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.pay-dialog-btn {
|
||||
width: 320rpx;
|
||||
height: 70rpx;
|
||||
margin-bottom: 40rpx;
|
||||
background: linear-gradient(90deg, #0090FF 0%, #2E9FFF 100%);
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
border-radius: 35rpx;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.province-input {
|
||||
background: #EEEEEE;
|
||||
border-radius: 5rpx;
|
||||
width: 43rpx;
|
||||
height: 53rpx;
|
||||
margin-right: 28rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
color: #222;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.province-keyboard-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.province-keyboard-box {
|
||||
width: 600rpx;
|
||||
background: #fff;
|
||||
border-radius: 28rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
|
||||
padding: 48rpx 36rpx 36rpx 36rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.province-keyboard-title {
|
||||
font-size: 32rpx;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.province-keyboard-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 18rpx;
|
||||
justify-content: center;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.province-keyboard-btn {
|
||||
width: 80rpx;
|
||||
height: 60rpx;
|
||||
background: #F7F8FA;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
margin-bottom: 8rpx;
|
||||
cursor: pointer;
|
||||
border: 1rpx solid #eee;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.province-keyboard-btn:active {
|
||||
background: #e6f0ff;
|
||||
}
|
||||
|
||||
.province-keyboard-cancel {
|
||||
width: 320rpx;
|
||||
height: 60rpx;
|
||||
background: #eee;
|
||||
color: #222;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
border-radius: 30rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.mine-list-arrow {
|
||||
width: 18rpx;
|
||||
height: 28rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
</style>
|
127
pages/sys/user/myPayment/paymentRecords.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<view class="page-wrapper">
|
||||
<!-- 可滚动内容区 -->
|
||||
<view class="scroll-content">
|
||||
<!-- 列表区 -->
|
||||
<view class="records-list">
|
||||
<view v-for="(item, idx) in records" :key="idx" class="records-card">
|
||||
<view class="records-row">
|
||||
<view class="records-car">{{ item.car }}</view>
|
||||
<view class="records-fee">¥{{ item.fee }}</view>
|
||||
</view>
|
||||
<view class="records-time">{{ item.time }}<text v-if="idx === 0">——{{ item.time }}</text></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部客服 -->
|
||||
<view class="records-service">
|
||||
<image src="/static/ic_payment_record_01.png" class="records-service-icon" />
|
||||
<text class="records-service-text">有疑问请联系客服</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
records: [
|
||||
{ car: '渝A·B8889', fee: '11.84', time: '2025-07-04 15:23:45' },
|
||||
{ car: '渝A·B8889', fee: '11.84', time: '2025-07-04 15:23:45' },
|
||||
{ car: '渝A·B8889', fee: '11.84', time: '2025-07-04 15:23:45' },
|
||||
{ car: '渝A·B8889', fee: '11.84', time: '2025-07-04 15:23:45' },
|
||||
{ car: '渝A·B8889', fee: '11.84', time: '2025-07-04 15:23:45' },
|
||||
{ car: '渝A·B8889', fee: '11.84', time: '2025-07-04 15:23:45' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrapper {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background: #f7f7f7;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
.records-navbar {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.records-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
.records-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
}
|
||||
.records-list {
|
||||
margin: 32rpx 0 0 0;
|
||||
padding: 40rpx 24rpx;
|
||||
}
|
||||
.records-card {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 24rpx;
|
||||
padding: 32rpx 32rpx 24rpx 32rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.03);
|
||||
border: none;
|
||||
}
|
||||
.records-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.records-car {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
}
|
||||
.records-fee {
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
font-weight: 500;
|
||||
}
|
||||
.records-time {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
.records-service {
|
||||
margin-top: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.records-service-icon {
|
||||
width: 26rpx;
|
||||
height: 29rpx;
|
||||
margin-right: 6rpx;
|
||||
}
|
||||
.records-service-text {
|
||||
color: #2186FF;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
507
pages/sys/user/myRecord/myRecord.vue
Normal file
@@ -0,0 +1,507 @@
|
||||
<template>
|
||||
<view class="my-record-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="header">
|
||||
<image class="back-btn" src="/static/ic_back.png" @click="goBack" />
|
||||
<text class="page-title">我的考勤</text>
|
||||
</view>
|
||||
|
||||
<!-- 月份标题和切换 -->
|
||||
<view class="month-header">
|
||||
<view class="month-nav">
|
||||
<view class="month-arrow" @click="prevMonth">
|
||||
<image class="arrow-icon" src="/static/ic_arrow_gray.webp" mode="aspectFit" style="transform: rotate(180deg)" />
|
||||
</view>
|
||||
<text class="month-title">{{ currentYear }}年{{ currentMonth }}月</text>
|
||||
<view class="month-arrow" @click="nextMonth">
|
||||
<image class="arrow-icon" src="/static/ic_arrow_gray.webp" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 考勤统计 -->
|
||||
<view class="attendance-stats">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">17</text>
|
||||
<text class="stat-label">出勤天数</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value orange">2</text>
|
||||
<text class="stat-label">迟到</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value orange">1</text>
|
||||
<text class="stat-label">早退</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">0</text>
|
||||
<text class="stat-label">补卡</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日历 -->
|
||||
<view class="calendar">
|
||||
<view class="weekdays">
|
||||
<text v-for="day in weekdays" :key="day" class="weekday">{{ day }}</text>
|
||||
</view>
|
||||
<view class="dates" v-if="calendarExpanded">
|
||||
<view
|
||||
v-for="(date, index) in allDates"
|
||||
:key="index"
|
||||
:class="getDateClass(date)"
|
||||
@click="selectDate(date)"
|
||||
>
|
||||
<text v-if="date.value" class="date-text">{{ date.value }}</text>
|
||||
<view v-if="date.hasRecord" class="record-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="dates" v-else>
|
||||
<view
|
||||
v-for="(date, index) in currentWeekDates"
|
||||
:key="index"
|
||||
:class="getDateClass(date)"
|
||||
@click="selectDate(date)"
|
||||
>
|
||||
<text v-if="date.value" class="date-text">{{ date.value }}</text>
|
||||
<view v-if="date.hasRecord" class="record-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="calendar-toggle" @click="toggleCalendar">
|
||||
<text class="toggle-text">{{ calendarExpanded ? '收起' : '展开' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 固定班次 -->
|
||||
<view class="fixed-shifts">
|
||||
<text class="shifts-title">固定班次</text>
|
||||
|
||||
<view class="shift-item">
|
||||
<view class="shift-time">
|
||||
<view class="time-dot"></view>
|
||||
<text class="time-text">应上班 09:00</text>
|
||||
</view>
|
||||
<view class="record leave-record">
|
||||
<text class="record-text">已请假 09:00—12:00</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="shift-item">
|
||||
<view class="shift-time">
|
||||
<view class="time-dot"></view>
|
||||
<text class="time-text">应下班 18:00</text>
|
||||
</view>
|
||||
<view class="record clock-record">
|
||||
<text class="record-text">已打卡 18:02:18</text>
|
||||
<text class="location">@某综合服务中心1栋</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 我的考勤页面
|
||||
* @author lyc
|
||||
* @description 显示用户考勤记录,包含可展开收缩的日历
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 星期标题
|
||||
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
// 日历是否展开
|
||||
calendarExpanded: false,
|
||||
// 当前选中的日期
|
||||
selectedDate: 8,
|
||||
// 当前年份
|
||||
currentYear: 2025,
|
||||
// 当前月份
|
||||
currentMonth: 7,
|
||||
// 完整月份日期数据
|
||||
allDates: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 当前周的日期(收缩状态显示)
|
||||
currentWeekDates() {
|
||||
// 找到选中日期所在的周
|
||||
const selectedIndex = this.allDates.findIndex(date => date.selected);
|
||||
if (selectedIndex === -1) return this.allDates.slice(0, 7);
|
||||
const startOfWeek = Math.floor(selectedIndex / 7) * 7;
|
||||
return this.allDates.slice(startOfWeek, startOfWeek + 7);
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// 初始化日历数据
|
||||
this.generateCalendarDates();
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 返回上一页
|
||||
*/
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
|
||||
/**
|
||||
* 切换日历展开/收缩状态
|
||||
*/
|
||||
toggleCalendar() {
|
||||
this.calendarExpanded = !this.calendarExpanded;
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择日期
|
||||
* @param {Object} date 日期对象
|
||||
*/
|
||||
selectDate(date) {
|
||||
if (!date.value) return;
|
||||
|
||||
// 清除之前选中的日期
|
||||
this.allDates.forEach(d => d.selected = false);
|
||||
// 设置新选中的日期
|
||||
date.selected = true;
|
||||
this.selectedDate = date.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取日期样式类名
|
||||
* @param {Object} date 日期对象
|
||||
* @returns {Object} 样式类名对象
|
||||
*/
|
||||
getDateClass(date) {
|
||||
return {
|
||||
'date-item': true,
|
||||
'selected': date.selected,
|
||||
'has-record': date.hasRecord,
|
||||
'empty': !date.value
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 切换到上一个月
|
||||
*/
|
||||
prevMonth() {
|
||||
if (this.currentMonth === 1) {
|
||||
this.currentYear--;
|
||||
this.currentMonth = 12;
|
||||
} else {
|
||||
this.currentMonth--;
|
||||
}
|
||||
this.generateCalendarDates();
|
||||
},
|
||||
|
||||
/**
|
||||
* 切换到下一个月
|
||||
*/
|
||||
nextMonth() {
|
||||
if (this.currentMonth === 12) {
|
||||
this.currentYear++;
|
||||
this.currentMonth = 1;
|
||||
} else {
|
||||
this.currentMonth++;
|
||||
}
|
||||
this.generateCalendarDates();
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成日历数据
|
||||
*/
|
||||
generateCalendarDates() {
|
||||
const year = this.currentYear;
|
||||
const month = this.currentMonth;
|
||||
|
||||
// 获取当月第一天是星期几
|
||||
const firstDay = new Date(year, month - 1, 1).getDay();
|
||||
|
||||
// 获取当月总天数
|
||||
const daysInMonth = new Date(year, month, 0).getDate();
|
||||
|
||||
// 清空日历数据
|
||||
this.allDates = [];
|
||||
|
||||
// 添加上月的空白日期
|
||||
for (let i = 0; i < firstDay; i++) {
|
||||
this.allDates.push({ value: null });
|
||||
}
|
||||
|
||||
// 添加当月日期
|
||||
for (let i = 1; i <= daysInMonth; i++) {
|
||||
// 模拟考勤记录数据,这里假设前20天有考勤记录
|
||||
const hasRecord = i <= 20;
|
||||
// 默认选中当月8号
|
||||
const selected = i === 8 && month === 7 && year === 2025;
|
||||
|
||||
this.allDates.push({
|
||||
value: i,
|
||||
hasRecord,
|
||||
selected
|
||||
});
|
||||
}
|
||||
|
||||
// 计算需要添加的下月空白日期数量,使总数为7的倍数
|
||||
const remainingDays = 7 - (this.allDates.length % 7);
|
||||
if (remainingDays < 7) {
|
||||
for (let i = 0; i < remainingDays; i++) {
|
||||
this.allDates.push({ value: null });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-record-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部导航栏 */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
/* 月份标题和导航 */
|
||||
.month-header {
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.month-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.month-arrow {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.month-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 考勤统计 */
|
||||
.attendance-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 40rpx 30rpx;
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-value.orange {
|
||||
color: #ff6b35;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 日历 */
|
||||
.calendar {
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.weekdays {
|
||||
display: flex;
|
||||
background-color: #f8f8f8;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.weekday {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.dates {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.date-item {
|
||||
width: 14.28%;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.date-item.empty {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.date-item.selected {
|
||||
background-color: #007aff;
|
||||
border-radius: 50%;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin: 10rpx auto;
|
||||
}
|
||||
|
||||
.date-item.selected .date-text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.record-dot {
|
||||
position: absolute;
|
||||
bottom: 8rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
background-color: #007aff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.date-item.selected .record-dot {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.calendar-toggle {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
border-top: 1rpx solid #e0e0e0;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.toggle-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 固定班次 */
|
||||
.fixed-shifts {
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.shifts-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.shift-item {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.shift-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.shift-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.time-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background-color: #ff6b35;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.time-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.record {
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
margin-left: 28rpx;
|
||||
}
|
||||
|
||||
.leave-record {
|
||||
background-color: #fff7f0;
|
||||
border-color: #ffb366;
|
||||
}
|
||||
|
||||
.clock-record {
|
||||
background-color: #f0f9ff;
|
||||
border-color: #66b3ff;
|
||||
}
|
||||
|
||||
.record-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.location {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
405
pages/sys/user/myRecord/myRecord2.vue
Normal file
@@ -0,0 +1,405 @@
|
||||
<template>
|
||||
<view class="my-record-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="header">
|
||||
<image class="back-btn" src="/static/ic_back.png" @click="goBack" />
|
||||
<text class="page-title">我的考勤</text>
|
||||
</view>
|
||||
|
||||
<!-- 月份标题 -->
|
||||
<view class="month-header">
|
||||
<text class="month-title">2025年7月</text>
|
||||
</view>
|
||||
|
||||
<!-- 考勤统计 -->
|
||||
<view class="attendance-stats">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">17</text>
|
||||
<text class="stat-label">出勤天数</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value orange">2</text>
|
||||
<text class="stat-label">迟到</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value orange">1</text>
|
||||
<text class="stat-label">早退</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">0</text>
|
||||
<text class="stat-label">补卡</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日历 -->
|
||||
<view class="calendar">
|
||||
<view class="weekdays">
|
||||
<text v-for="day in weekdays" :key="day" class="weekday">{{ day }}</text>
|
||||
</view>
|
||||
<view class="dates" v-if="calendarExpanded">
|
||||
<view
|
||||
v-for="(date, index) in allDates"
|
||||
:key="index"
|
||||
:class="getDateClass(date)"
|
||||
@click="selectDate(date)"
|
||||
>
|
||||
<text v-if="date.value" class="date-text">{{ date.value }}</text>
|
||||
<view v-if="date.hasRecord" class="record-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="dates" v-else>
|
||||
<view
|
||||
v-for="(date, index) in currentWeekDates"
|
||||
:key="index"
|
||||
:class="getDateClass(date)"
|
||||
@click="selectDate(date)"
|
||||
>
|
||||
<text v-if="date.value" class="date-text">{{ date.value }}</text>
|
||||
<view v-if="date.hasRecord" class="record-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="calendar-toggle" @click="toggleCalendar">
|
||||
<text class="toggle-text">{{ calendarExpanded ? '收起' : '展开' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 固定班次 -->
|
||||
<view class="fixed-shifts">
|
||||
<text class="shifts-title">固定班次</text>
|
||||
|
||||
<view class="shift-item">
|
||||
<view class="shift-time">
|
||||
<view class="time-dot"></view>
|
||||
<text class="time-text">应上班 09:00</text>
|
||||
</view>
|
||||
<view class="record leave-record">
|
||||
<text class="record-text">已请假 09:00—12:00</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="shift-item">
|
||||
<view class="shift-time">
|
||||
<view class="time-dot"></view>
|
||||
<text class="time-text">应下班 18:00</text>
|
||||
</view>
|
||||
<view class="record clock-record">
|
||||
<text class="record-text">已打卡 18:02:18</text>
|
||||
<text class="location">@某综合服务中心1栋</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 我的考勤页面
|
||||
* @author lyc
|
||||
* @description 显示用户考勤记录,包含可展开收缩的日历
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 星期标题
|
||||
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
|
||||
// 日历是否展开
|
||||
calendarExpanded: false,
|
||||
// 当前选中的日期
|
||||
selectedDate: 8,
|
||||
// 完整月份日期数据
|
||||
allDates: [
|
||||
{ value: null }, { value: null }, { value: 1, hasRecord: true }, { value: 2, hasRecord: true }, { value: 3, hasRecord: true }, { value: 4, hasRecord: true }, { value: 5, hasRecord: true },
|
||||
{ value: 6, hasRecord: true }, { value: 7, hasRecord: true }, { value: 8, hasRecord: true, selected: true }, { value: 9, hasRecord: true }, { value: 10, hasRecord: true }, { value: 11, hasRecord: true }, { value: 12, hasRecord: true },
|
||||
{ value: 13, hasRecord: true }, { value: 14, hasRecord: true }, { value: 15, hasRecord: true }, { value: 16, hasRecord: true }, { value: 17 }, { value: 18 }, { value: 19 },
|
||||
{ value: 20 }, { value: 21 }, { value: 22 }, { value: 23 }, { value: 24 }, { value: 25 }, { value: 26 },
|
||||
{ value: 27 }, { value: 28 }, { value: 29 }, { value: 30 }, { value: 31 }, { value: null }, { value: null }
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 当前周的日期(收缩状态显示)
|
||||
currentWeekDates() {
|
||||
// 找到选中日期所在的周
|
||||
const selectedIndex = this.allDates.findIndex(date => date.selected);
|
||||
const startOfWeek = Math.floor(selectedIndex / 7) * 7;
|
||||
return this.allDates.slice(startOfWeek, startOfWeek + 7);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 返回上一页
|
||||
*/
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
|
||||
/**
|
||||
* 切换日历展开/收缩状态
|
||||
*/
|
||||
toggleCalendar() {
|
||||
this.calendarExpanded = !this.calendarExpanded;
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择日期
|
||||
* @param {Object} date 日期对象
|
||||
*/
|
||||
selectDate(date) {
|
||||
if (!date.value) return;
|
||||
|
||||
// 清除之前选中的日期
|
||||
this.allDates.forEach(d => d.selected = false);
|
||||
// 设置新选中的日期
|
||||
date.selected = true;
|
||||
this.selectedDate = date.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取日期样式类名
|
||||
* @param {Object} date 日期对象
|
||||
* @returns {Object} 样式类名对象
|
||||
*/
|
||||
getDateClass(date) {
|
||||
return {
|
||||
'date-item': true,
|
||||
'selected': date.selected,
|
||||
'has-record': date.hasRecord,
|
||||
'empty': !date.value
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-record-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 顶部导航栏 */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
/* 月份标题 */
|
||||
.month-header {
|
||||
padding: 30rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.month-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 考勤统计 */
|
||||
.attendance-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 40rpx 30rpx;
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-value.orange {
|
||||
color: #ff6b35;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 日历 */
|
||||
.calendar {
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.weekdays {
|
||||
display: flex;
|
||||
background-color: #f8f8f8;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.weekday {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.dates {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.date-item {
|
||||
width: 14.28%;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.date-item.empty {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.date-item.selected {
|
||||
background-color: #007aff;
|
||||
border-radius: 50%;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
margin: 10rpx auto;
|
||||
}
|
||||
|
||||
.date-item.selected .date-text {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.date-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.record-dot {
|
||||
position: absolute;
|
||||
bottom: 8rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
background-color: #007aff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.date-item.selected .record-dot {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.calendar-toggle {
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
border-top: 1rpx solid #e0e0e0;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.toggle-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 固定班次 */
|
||||
.fixed-shifts {
|
||||
margin: 20rpx 30rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.shifts-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.shift-item {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.shift-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.shift-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.time-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
background-color: #ff6b35;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.time-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.record {
|
||||
border: 2rpx dashed #e0e0e0;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
margin-left: 28rpx;
|
||||
}
|
||||
|
||||
.leave-record {
|
||||
background-color: #fff7f0;
|
||||
border-color: #ffb366;
|
||||
}
|
||||
|
||||
.clock-record {
|
||||
background-color: #f0f9ff;
|
||||
border-color: #66b3ff;
|
||||
}
|
||||
|
||||
.record-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.location {
|
||||
font-size: 24rpx;
|
||||
color: #007aff;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
299
pages/sys/user/myRepair/addRepair.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<view class="add-repair-container">
|
||||
<!-- 可滚动内容区 -->
|
||||
<view class="add-repair-scroll-content">
|
||||
<!-- 地址选择 -->
|
||||
<view class="add-repair-section">
|
||||
<view class="add-repair-address-btn">
|
||||
<view class="add-repair-address-text">请选择房屋所在地址</view>
|
||||
<image class="add-repair-address-img" src="/static/ic_add_repair_01.png" />
|
||||
</view>
|
||||
<view class="add-repair-detail">
|
||||
<view class="add-repair-detail1">详细地址 </view>
|
||||
<view class="add-repair-detail2">例1栋2单元101室1</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 报事报修类型 -->
|
||||
<view class="add-repair-section2">
|
||||
<view class="add-repair-label">报事报修</view>
|
||||
<view class="add-repair-type-list">
|
||||
<view v-for="(item, idx) in repairTypes" :key="idx"
|
||||
:class="['add-repair-type-btn', selectedType === item ? 'selected' : '']"
|
||||
@click="selectType(item)">{{ item }}</view>
|
||||
</view>
|
||||
<view class="add-repair-label2">其他服务</view>
|
||||
<view class="add-repair-type-list">
|
||||
<view v-for="(item, idx) in otherTypes" :key="idx" class="add-repair-type-btn">{{ item }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 问题详情 -->
|
||||
<view class="add-repair-section">
|
||||
<view class="add-repair-label">问题详情 <text class="add-repair-optional">(非必填)</text></view>
|
||||
<textarea class="add-repair-detail-textarea" placeholder="如果以上报事不能解决您的问题,可以在这里填写说明" />
|
||||
</view>
|
||||
<!-- 上传照片 -->
|
||||
<view class="add-repair-section">
|
||||
<view class="add-repair-label">上传照片 <text class="add-repair-optional">(非必填,最多三张)</text></view>
|
||||
<view class="add-repair-upload-list">
|
||||
<!-- 修改部分:添加点击事件和图片预览 -->
|
||||
<view
|
||||
class="add-repair-upload-box"
|
||||
@click="handleImageUpload"
|
||||
>
|
||||
<view class="add-repair-upload-plus">+</view>
|
||||
<view class="add-repair-upload-text">上传图片</view>
|
||||
</view>
|
||||
<!-- 显示已选图片 -->
|
||||
<view v-for="(image, index) in selectedImages" :key="index" class="add-repair-upload-box">
|
||||
<image :src="image.path" class="add-repair-upload-image" @click.stop="previewImage(image.path)" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 提交按钮 -->
|
||||
<button class="add-repair-submit-btn" @click="goRepaired">提交</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 导入MediaSelector和MediaType
|
||||
import MediaSelector, { MediaType } from '@/utils/mediaSelector';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
repairTypes: ['安装挂件', '维修下水', '维修水阀', '疏通管道', '维修线路', '更换灯泡', '维修门窗', '其他维修'],
|
||||
otherTypes: ['园区安保', '通水通电', '维修线路'],
|
||||
selectedType: '更换灯泡',
|
||||
selectedImages: [] // 存储已选图片
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectType(item) {
|
||||
this.selectedType = item;
|
||||
},
|
||||
// 新增:处理图片上传
|
||||
async handleImageUpload() {
|
||||
try {
|
||||
// 调用MediaSelector选择图片,最多选择3张
|
||||
const images = await MediaSelector.choose({
|
||||
type: MediaType.IMAGE,
|
||||
count: 3 - this.selectedImages.length // 根据剩余数量选择
|
||||
});
|
||||
// 将选择的图片添加到selectedImages数组
|
||||
this.selectedImages = [...this.selectedImages, ...images];
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
},
|
||||
// 预览图片
|
||||
previewImage(path) {
|
||||
MediaSelector.preview(path, MediaType.IMAGE);
|
||||
},
|
||||
goRepaired(){
|
||||
uni.navigateTo({ url: '/pages/mine/myRepair/repaired' });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.add-repair-container {
|
||||
height: 100vh;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.add-repair-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.add-repair-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.add-repair-scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.add-repair-section {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin: 22rpx 30rpx 0 30rpx;
|
||||
padding: 24rpx 46rpx 24rpx 44rpx;
|
||||
}
|
||||
|
||||
.add-repair-section2 {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin: 22rpx 30rpx 0 30rpx;
|
||||
padding: 24rpx 26rpx 24rpx 26rpx;
|
||||
}
|
||||
|
||||
.add-repair-address-btn {
|
||||
width: 100%;
|
||||
height: 48rpx;
|
||||
background: #fff;
|
||||
border: 2rpx solid #2186FF;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 30rpx;
|
||||
padding-left: 18rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.add-repair-address-text {
|
||||
font-size: 24rpx;
|
||||
color: #007CFF;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.add-repair-address-img {
|
||||
width: 11rpx;
|
||||
height: 21rpx;
|
||||
}
|
||||
|
||||
.add-repair-detail {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.add-repair-detail1 {
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.add-repair-detail2 {
|
||||
font-size: 24rpx;
|
||||
color: #676767;
|
||||
margin-left: 39rpx;
|
||||
}
|
||||
.add-repair-label {
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
font-weight: 500;
|
||||
margin-bottom: 41rpx;
|
||||
}
|
||||
|
||||
.add-repair-label2 {
|
||||
font-size: 32rpx;
|
||||
color: #000000;
|
||||
font-weight: 500;
|
||||
margin-bottom: 25rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
|
||||
|
||||
.add-repair-type-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 28rpx 21rpx;
|
||||
}
|
||||
|
||||
.add-repair-type-btn {
|
||||
flex: 0 0 calc((100% - 42rpx) / 3);
|
||||
box-sizing: border-box;
|
||||
height: 73rpx;
|
||||
background: #F2F7FF;
|
||||
color: #2186FF;
|
||||
font-size: 26rpx;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.add-repair-type-btn.selected {
|
||||
background: #2186FF;
|
||||
color: #fff;
|
||||
border: 2rpx solid #2186FF;
|
||||
}
|
||||
|
||||
.add-repair-type-btn.dashed {
|
||||
border: 2rpx dashed #BDBDBD;
|
||||
background: #fff;
|
||||
color: #2186FF;
|
||||
}
|
||||
|
||||
.add-repair-optional {
|
||||
color: #888;
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.add-repair-detail-textarea {
|
||||
width: 75vw;
|
||||
min-height: 120rpx;
|
||||
background: #F7F8FA;
|
||||
border-radius: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: #888;
|
||||
padding: 18rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.add-repair-upload-list {
|
||||
display: flex;
|
||||
gap: 18rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.add-repair-upload-box {
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border: 2rpx dashed #BDBDBD;
|
||||
border-radius: 8rpx;
|
||||
background: #fafbfc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.add-repair-upload-plus {
|
||||
font-size: 60rpx;
|
||||
color: #BDBDBD;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.add-repair-upload-text {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.add-repair-submit-btn {
|
||||
width: 90vw;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, #2186FF 0%, #4FC3F7 100%);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin: 48rpx auto 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
/* 新增图片预览样式 */
|
||||
.add-repair-upload-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
</style>
|
451
pages/sys/user/myRepair/myRepair.vue
Normal file
@@ -0,0 +1,451 @@
|
||||
<template>
|
||||
<view class="repair-container">
|
||||
<!-- 可滚动内容区 -->
|
||||
<scroll-view scroll-y class="repair-scroll-content" @scroll="handleScroll">
|
||||
<!-- 空状态 -->
|
||||
<view v-if="records.length === 0" class="repair-empty-box">
|
||||
<view class="repair-empty-img-box">
|
||||
<image src="/static/ic_my_repair_01.png" class="repair-empty-img" />
|
||||
</view>
|
||||
<view class="repair-add-btn-box">
|
||||
<image src="/static/ic_my_repair_02.png" class="repair-add-btn" @click="addRepair" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 有数据时 -->
|
||||
<view v-else class="repair-list-box">
|
||||
<view v-for="(item, idx) in records" :key="idx" class="repair-card" @click="showDetail(item)">
|
||||
<view class="repair-row">
|
||||
<view class="repair-no">工单号:{{ item.no }}</view>
|
||||
<view class="repair-status" :class="item.statusClass">{{ item.statusText }}</view>
|
||||
</view>
|
||||
<image class="repair-line-image" src="/static/ic_my_repair_03.png"/>
|
||||
<view class="repair-info">建立时间:{{ item.time }}</view>
|
||||
<view class="repair-info">报事内容:{{ item.content }}</view>
|
||||
<view class="repair-info">报事位置:{{ item.addr }}</view>
|
||||
<view v-if="item.statusText === '已结束'" class="repair-eval-btn eval-btn-right">服务评价</view>
|
||||
</view>
|
||||
<!-- 悬浮新增按钮 -->
|
||||
<image src="/static/ic_my_repair_02.png" :class="['repair-add-btn-fixed', { 'hide': isAddBtnHidden }]" @click="addRepair" />
|
||||
</view>
|
||||
</scroll-view>
|
||||
<!-- 详情弹窗 -->
|
||||
<view v-if="showDetailDialog" class="repair-detail-mask" @click.self="closeDetail">
|
||||
<view class="repair-detail-dialog">
|
||||
<view class="repair-detail-title">报事详情
|
||||
<image src="/static/ic_close_01.png" class="repair-detail-close" @click.stop="closeDetail" />
|
||||
</view>
|
||||
<view class="repair-detail-progress-box">
|
||||
<view class="repair-detail-progress">
|
||||
<view v-for="(step, idx) in progressSteps" :key="idx" class="repair-detail-step">
|
||||
<view :class="['repair-detail-dot', detailStep >= idx ? 'active' : '', (detailStep === idx && detailStatus !== '已结束') ? 'current' : '']"></view>
|
||||
<view v-if="idx < progressSteps.length - 1" :class="['repair-detail-line', detailStep > idx ? 'active' : '']"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="repair-detail-progress-labels">
|
||||
<view v-for="(step, idx) in progressSteps" :key="idx" class="repair-detail-label">{{ step }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="repair-detail-info">建立时间:{{ detailItem.time }}</view>
|
||||
<view class="repair-detail-info">报事内容:{{ detailItem.content }}</view>
|
||||
<view class="repair-detail-info">报事位置:{{ detailItem.addr }}</view>
|
||||
<button v-if="detailItem.statusText === '已结束'" class="repair-detail-btn" @click="goTEvaluate">评价服务</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 空数组可切换空状态
|
||||
records: [{
|
||||
no: '20250628147856687',
|
||||
time: '2025-07-02 15:24:36',
|
||||
content: '室内无气,未欠费',
|
||||
addr: '68栋1单元8-9',
|
||||
statusText: '待处理',
|
||||
statusClass: 'pending'
|
||||
},
|
||||
{
|
||||
no: '20250628147856687',
|
||||
time: '2025-07-02 15:24:36',
|
||||
content: '室内无气,未欠费',
|
||||
addr: '68栋1单元8-9',
|
||||
statusText: '已结束',
|
||||
statusClass: 'done'
|
||||
},
|
||||
{
|
||||
no: '20250628147856687',
|
||||
time: '2025-07-02 15:24:36',
|
||||
content: '室内无气,未欠费',
|
||||
addr: '68栋1单元8-9',
|
||||
statusText: '处理中',
|
||||
statusClass: 'doing'
|
||||
},
|
||||
{
|
||||
no: '20250628147856687',
|
||||
time: '2025-07-02 15:24:36',
|
||||
content: '室内无气,未欠费',
|
||||
addr: '68栋1单元8-9',
|
||||
statusText: '已结束',
|
||||
statusClass: 'done'
|
||||
},
|
||||
{
|
||||
no: '20250628147856687',
|
||||
time: '2025-07-02 15:24:36',
|
||||
content: '室内无气,未欠费',
|
||||
addr: '68栋1单元8-9',
|
||||
statusText: '已结束',
|
||||
statusClass: 'done'
|
||||
}
|
||||
],
|
||||
showDetailDialog: false,
|
||||
detailItem: {},
|
||||
detailStep: 0,
|
||||
detailStatus: '',
|
||||
progressSteps: ['创建报事', '待处理', '处理中', '已结束'],
|
||||
lastScrollTop: 0,
|
||||
isAddBtnHidden: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
addRepair() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/sys/user/myRepair/addRepair'
|
||||
});
|
||||
},
|
||||
showDetail(item) {
|
||||
this.detailItem = item;
|
||||
// 进度映射
|
||||
if(item.statusText === '待处理') { this.detailStep = 1; this.detailStatus = '待处理'; }
|
||||
else if(item.statusText === '处理中') { this.detailStep = 2; this.detailStatus = '处理中'; }
|
||||
else if(item.statusText === '已结束') { this.detailStep = 3; this.detailStatus = '已结束'; }
|
||||
else { this.detailStep = 0; this.detailStatus = '创建报事'; }
|
||||
this.showDetailDialog = true;
|
||||
},
|
||||
closeDetail() {
|
||||
this.showDetailDialog = false;
|
||||
},
|
||||
goTEvaluate(){
|
||||
uni.navigateTo({
|
||||
url: '/pages/sys/user/myRepair/repairEvaluate'
|
||||
});
|
||||
},
|
||||
handleScroll(e) {
|
||||
const scrollTop = e.detail.scrollTop;
|
||||
// 为了避免过于频繁的触发,可以设置一个阈值
|
||||
if (Math.abs(scrollTop - this.lastScrollTop) < 20) {
|
||||
return;
|
||||
}
|
||||
if (scrollTop > this.lastScrollTop && scrollTop > 50) {
|
||||
// 向下滚动,隐藏按钮
|
||||
this.isAddBtnHidden = true;
|
||||
} else {
|
||||
// 向上滚动,显示按钮
|
||||
this.isAddBtnHidden = false;
|
||||
}
|
||||
this.lastScrollTop = scrollTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.repair-container {
|
||||
height: 100vh;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.repair-navbar {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
flex-shrink: 0; /* 防止被压缩 */
|
||||
}
|
||||
|
||||
.repair-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.repair-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.repair-scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.repair-empty-box {
|
||||
margin: 48rpx 24rpx 0 24rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.repair-empty-img-box {
|
||||
border: 2rpx dashed #BDBDBD;
|
||||
border-radius: 8rpx;
|
||||
background: #fafbfc;
|
||||
width: 100%;
|
||||
min-height: 220rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.repair-empty-img {
|
||||
width: 90%;
|
||||
max-width: 400rpx;
|
||||
height: 180rpx;
|
||||
object-fit: contain;
|
||||
margin: 24rpx auto;
|
||||
}
|
||||
|
||||
.repair-add-btn-box {
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
bottom: -40rpx;
|
||||
}
|
||||
|
||||
.repair-add-btn {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border: 2rpx dashed #BDBDBD;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.repair-list-box {
|
||||
margin: 32rpx 0 0 0;
|
||||
padding: 0 24rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.repair-card {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
|
||||
padding-top: 25rpx;
|
||||
padding-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.repair-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
margin-top: 25rpx;
|
||||
margin-left: 19rpx;
|
||||
margin-right: 50rpx;
|
||||
}
|
||||
|
||||
.repair-no {
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.repair-status {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.repair-line-image{
|
||||
margin: left 29rpx ;
|
||||
margin-right: 39rpx;
|
||||
height: 2rpx;
|
||||
margin-bottom: 29rpx;
|
||||
}
|
||||
|
||||
.repair-status.pending {
|
||||
color: #FF9800;
|
||||
}
|
||||
|
||||
.repair-status.doing {
|
||||
color: #05C58C;
|
||||
}
|
||||
|
||||
.repair-status.done {
|
||||
color: #BDBDBD;
|
||||
}
|
||||
|
||||
.repair-info {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
margin-bottom: 30rpx;
|
||||
margin-left: 47rpx;
|
||||
}
|
||||
|
||||
.repair-eval-btn {
|
||||
margin-top: -20rpx;
|
||||
margin-bottom: 0;
|
||||
margin-left: auto;
|
||||
margin-right: 44rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0 18rpx;
|
||||
height: 44rpx;
|
||||
line-height: 44rpx;
|
||||
border-radius: 8rpx;
|
||||
border: 2rpx solid #2186FF;
|
||||
color: #2186FF;
|
||||
font-size: 24rpx;
|
||||
background: #fff;
|
||||
font-weight: 500;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.repair-add-btn-fixed {
|
||||
position: fixed;
|
||||
right: 40rpx;
|
||||
bottom: 80rpx;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
z-index: 100;
|
||||
transition: transform 0.3s ease;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.repair-add-btn-fixed.hide {
|
||||
transform: translateX(200%);
|
||||
}
|
||||
|
||||
.repair-detail-mask {
|
||||
position: fixed;
|
||||
left: 0; top: 0; right: 0; bottom: 0;
|
||||
background: rgba(0,0,0,0.45);
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
.repair-detail-dialog {
|
||||
width: 100vw;
|
||||
background: #fff;
|
||||
border-radius: 18rpx 18rpx 0 0;
|
||||
box-shadow: 0 -2rpx 24rpx rgba(0,0,0,0.10);
|
||||
padding: 52rpx 56rpx 69rpx 56rpx;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.repair-detail-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
.repair-detail-close {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.repair-detail-progress-box {
|
||||
height: 107rpx;
|
||||
margin-bottom: 41rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
}
|
||||
.repair-detail-progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5rpx;
|
||||
margin-left: 70rpx;
|
||||
width: 100%;
|
||||
}
|
||||
.repair-detail-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
.repair-detail-dot {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
border-radius: 50%;
|
||||
background: #BDBDBD;
|
||||
border: 2rpx solid #BDBDBD;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.repair-detail-dot.active {
|
||||
background: #2186FF;
|
||||
border-color: #2186FF;
|
||||
}
|
||||
.repair-detail-dot.current {
|
||||
background: #EF8D00;
|
||||
border-color: #EF8D00;
|
||||
}
|
||||
.repair-detail-line {
|
||||
flex: 1;
|
||||
height: 4rpx;
|
||||
background: #BDBDBD;
|
||||
margin: 0 2rpx;
|
||||
z-index: 1;
|
||||
}
|
||||
.repair-detail-line.active {
|
||||
background: #2186FF;
|
||||
}
|
||||
.repair-detail-progress-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.repair-detail-label {
|
||||
font-size: 22rpx;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
top: 8rpx;
|
||||
}
|
||||
.repair-detail-info {
|
||||
font-size: 26rpx;
|
||||
color: #222;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.repair-detail-btn {
|
||||
width:445rpx;
|
||||
height: 73rpx;
|
||||
background: linear-gradient(90deg, #005DE9 0%, #4B9BFF 100%);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 30rpx;
|
||||
margin-top: 32rpx;
|
||||
font-weight: 600;
|
||||
margin-top: 100rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
/* 让服务评价按钮靠右 */
|
||||
.eval-btn-right {
|
||||
margin-left: auto;
|
||||
display: block;
|
||||
width: fit-content;
|
||||
}
|
172
pages/sys/user/myRepair/repairEvaluate.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="evaluate-container">
|
||||
|
||||
<!-- 评分项 -->
|
||||
<view class="evaluate-list">
|
||||
<view class="evaluate-row">
|
||||
<text class="evaluate-label">服务评价</text>
|
||||
<view class="evaluate-stars">
|
||||
<image v-for="i in 5" :key="i" :src="score >= i ? '/static/ic_evaluate_select.png' : '/static/ic_evaluate_disselect.png'" class="evaluate-star" @click="score = i" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="evaluate-desc">- 具体说说看 -</view>
|
||||
<view class="evaluate-row">
|
||||
<text class="evaluate-label">专业性</text>
|
||||
<view class="evaluate-stars">
|
||||
<image v-for="i in 5" :key="i" :src="proScore >= i ? '/static/ic_evaluate_select.png' : '/static/ic_evaluate_disselect.png'" class="evaluate-star" @click="proScore = i" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="evaluate-row">
|
||||
<text class="evaluate-label">服务态度</text>
|
||||
<view class="evaluate-stars">
|
||||
<image v-for="i in 5" :key="i" :src="attitudeScore >= i ? '/static/ic_evaluate_select.png' : '/static/ic_evaluate_disselect.png'" class="evaluate-star" @click="attitudeScore = i" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="evaluate-row">
|
||||
<text class="evaluate-label">时效性</text>
|
||||
<view class="evaluate-stars">
|
||||
<image v-for="i in 5" :key="i" :src="timelyScore >= i ? '/static/ic_evaluate_select.png' : '/static/ic_evaluate_disselect.png'" class="evaluate-star" @click="timelyScore = i" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 标签选择 -->
|
||||
<view class="evaluate-tag-title">- 选择或自定义任一标签 -</view>
|
||||
<view class="evaluate-tags">
|
||||
<view v-for="(tag, idx) in tags" :key="idx" :class="['evaluate-tag', selectedTags.includes(tag) ? 'selected' : '']" @click="toggleTag(tag)">{{ tag }}</view>
|
||||
</view>
|
||||
<!-- 输入框 -->
|
||||
<textarea class="evaluate-textarea" placeholder="说点什么吧..." v-model="comment" />
|
||||
<!-- 提交按钮 -->
|
||||
<button class="evaluate-btn">提交</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
score: 4,
|
||||
proScore: 5,
|
||||
attitudeScore: 4,
|
||||
timelyScore: 4,
|
||||
tags: ['专业性强', '态度谦和', '声音甜美', '速度很快'],
|
||||
selectedTags: ['专业性强', '态度谦和'],
|
||||
comment: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleTag(tag) {
|
||||
if (this.selectedTags.includes(tag)) {
|
||||
this.selectedTags = this.selectedTags.filter(t => t !== tag)
|
||||
} else {
|
||||
this.selectedTags.push(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.evaluate-container {
|
||||
min-height: 100vh;
|
||||
background: #fff;
|
||||
padding-bottom: 40rpx;
|
||||
/* 防止在iOS等设备上滑动到顶部或底部时出现回弹效果 */
|
||||
overscroll-behavior-y: contain;
|
||||
}
|
||||
|
||||
.evaluate-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
.evaluate-title {
|
||||
font-size: 30rpx;
|
||||
color: #000;
|
||||
}
|
||||
.evaluate-list {
|
||||
margin: 0 53rpx 0 40rpx;
|
||||
}
|
||||
.evaluate-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 38rpx;
|
||||
}
|
||||
.evaluate-label {
|
||||
font-size: 30rpx;
|
||||
color: #222;
|
||||
width: 160rpx;
|
||||
text-align: left;
|
||||
}
|
||||
.evaluate-stars {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.evaluate-star {
|
||||
width: 36rpx;
|
||||
height: 34rpx;
|
||||
margin-right: 36rpx;
|
||||
}
|
||||
.evaluate-desc {
|
||||
color: #BDBDBD;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
margin-top: 67rpx;
|
||||
margin-bottom: 57rpx;
|
||||
}
|
||||
.evaluate-tag-title {
|
||||
color: #BDBDBD;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
margin: 60rpx 0 0 0;
|
||||
}
|
||||
.evaluate-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
margin: 52rpx 25rpx 0 25rpx;
|
||||
}
|
||||
.evaluate-tag {
|
||||
flex: 0 0 calc((100% - 60rpx) / 4);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 64rpx;
|
||||
border-radius: 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
background: #F2F2F2;
|
||||
}
|
||||
.evaluate-tag.selected {
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.evaluate-textarea {
|
||||
width: 85vw;
|
||||
min-height: 120rpx;
|
||||
background: #F5F6F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 26rpx;
|
||||
color: #B6C2CE;
|
||||
padding: 23rpx 27rpx 23rpx 27rpx;
|
||||
margin: 49rpx auto 0 auto;
|
||||
display: block;
|
||||
}
|
||||
.evaluate-btn {
|
||||
width: 80vw;
|
||||
height: 88rpx;
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
margin: 137rpx auto 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.18);
|
||||
}
|
||||
</style>
|
107
pages/sys/user/myRepair/repaired.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<view class="repaired-container">
|
||||
<!-- 顶部栏 -->
|
||||
<view class="repaired-navbar">
|
||||
<image src="/static/ic_back.png" class="repaired-back" @click="goBack" />
|
||||
<text class="repaired-progress" @click="goProgress">查看进度</text>
|
||||
</view>
|
||||
<!-- 成功图标 -->
|
||||
<view class="repaired-icon-box">
|
||||
<image src="/static/ic_repaired_01.png" class="repaired-icon" />
|
||||
</view>
|
||||
<!-- 提交成功文字 -->
|
||||
<view class="repaired-title">提交成功</view>
|
||||
<view class="repaired-desc">提交成功后我们将及时为您服务</view>
|
||||
<!-- 返回首页按钮 -->
|
||||
<button class="repaired-btn" @click="goHome">返回首页</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
goProgress() {
|
||||
// 跳转到进度页面
|
||||
uni.showToast({ title: '查看进度', icon: 'none' });
|
||||
},
|
||||
goHome() {
|
||||
uni.switchTab({ url: '/pages/home/home' });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.repaired-container {
|
||||
min-height: 100vh;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.repaired-navbar {
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
.repaired-back {
|
||||
width: 18rpx;
|
||||
height: 32rpx;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
.repaired-progress {
|
||||
position: absolute;
|
||||
right: 36rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
.repaired-icon-box {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
margin: 113rpx auto 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.repaired-icon {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
}
|
||||
.repaired-title {
|
||||
margin-top: 96rpx;
|
||||
font-size: 38rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
}
|
||||
.repaired-desc {
|
||||
margin-top: 39rpx;
|
||||
font-size: 28rpx;
|
||||
color: rgba(51,51,51,0.5);
|
||||
text-align: center;
|
||||
}
|
||||
.repaired-btn {
|
||||
width: 524rpx;
|
||||
height: 92rpx;
|
||||
background: linear-gradient(90deg, #00C7FF 0%, #0096FF 100%);
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
border-radius: 22rpx;
|
||||
margin: 246rpx auto 0 auto;
|
||||
box-shadow: 0 15rpx 24rpx 0 rgba(0,199,255,0.18), 0 8rpx 24rpx 0 rgba(0,150,255,0.18);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
</style>
|
359
pages/sys/user/myVisitor/creatVisitor.vue
Normal file
@@ -0,0 +1,359 @@
|
||||
<template>
|
||||
<view class="cv-container">
|
||||
|
||||
<!-- 可滚动内容区 -->
|
||||
<view class="cv-scroll-content">
|
||||
<!-- 访客信息 -->
|
||||
<view class="info">
|
||||
<view class="cv-section-title">访客信息</view>
|
||||
<view class="cv-avatar-upload" @click="chooseAvatar">
|
||||
<view v-if="!form.avatar" class="cv-avatar-placeholder">上传正脸照</view>
|
||||
<image v-else :src="form.avatar" class="cv-avatar-img" />
|
||||
</view>
|
||||
<input class="cv-input-name" placeholder="请输入姓名" v-model="form.name" />
|
||||
<input class="cv-input-phone" placeholder="请输入来访人电话" v-model="form.phone" />
|
||||
<input class="cv-input" placeholder="请输入来访人身份证/军官证" v-model="form.idCard" />
|
||||
</view>
|
||||
<!-- 选择来访目的 -->
|
||||
<view class="cv-section">
|
||||
<view class="cv-section-title">选择来访目的</view>
|
||||
<view class="cv-purpose-list">
|
||||
<view v-for="(item, idx) in purposes" :key="idx"
|
||||
:class="['cv-purpose-btn', {active: form.purpose === item}]" @click="form.purpose = item">{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="cv-room-select" @click="chooseRoom">
|
||||
<text>{{ form.room || '请选择访问楼栋及房间号' }}</text>
|
||||
<text class="cv-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 来访时间 -->
|
||||
<view class="cv-section">
|
||||
<view class="cv-section-title">来访时间</view>
|
||||
<view class="cv-time-list">
|
||||
<view v-for="(item, idx) in times" :key="idx" :class="['cv-time-btn', {active: form.time === item}]"
|
||||
@click="form.time = item">{{ item }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 是否预约车位 -->
|
||||
<view class="cv-section">
|
||||
<view class="cv-parking-row">
|
||||
<view class="cv-section-title">是否预约车位</view>
|
||||
<view class="cv-radio-label" @click="form.parking = true">
|
||||
<view :class="['cv-radio-custom', {checked: form.parking === true}]" />
|
||||
<text>是</text>
|
||||
</view>
|
||||
<view class="cv-radio-label" @click="form.parking = false">
|
||||
<view :class="['cv-radio-custom', {checked: form.parking === false}]" />
|
||||
<text>否</text>
|
||||
</view>
|
||||
<text class="cv-parking-count">
|
||||
<text class="cv-parking-num">50</text><text class="cv-parking-total">/100</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="cv-room-select" @click="chooseCarNumber">
|
||||
<text>{{ form.carNumber || '请选择车牌号' }}</text>
|
||||
<text class="cv-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 提交按钮 -->
|
||||
<button class="cv-submit-btn">提交</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
name: '',
|
||||
phone: '',
|
||||
idCard: '',
|
||||
avatar: '',
|
||||
purpose: '',
|
||||
room: '',
|
||||
time: '',
|
||||
parking: false,
|
||||
carNumber: ''
|
||||
},
|
||||
purposes: ['商务合作', '园区参观', '面试签到', '装修放行', '家政服务', '送货上门'],
|
||||
times: ['今天(2025-07-04)', '明天(2025-07-04)']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
chooseAvatar() {
|
||||
// 这里可集成uni.chooseImage
|
||||
},
|
||||
chooseRoom() {
|
||||
// 这里可弹出选择房间号
|
||||
},
|
||||
chooseCarNumber() {
|
||||
// 这里可弹出选择车牌号
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cv-container {
|
||||
background: #fff;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cv-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.cv-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.cv-scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.cv-section {
|
||||
margin: 36rpx 56rpx 0 56rpx;
|
||||
}
|
||||
|
||||
.info {
|
||||
position: relative;
|
||||
margin: 36rpx 56rpx 0 56rpx;
|
||||
}
|
||||
|
||||
.cv-section-title {
|
||||
font-size: 32rpx;
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
.cv-inputs {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18rpx;
|
||||
}
|
||||
|
||||
.cv-input-name {
|
||||
width: 233rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
margin-top: 23rpx;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cv-input-phone {
|
||||
width: 363rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cv-input {
|
||||
width: 435rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cv-avatar-upload {
|
||||
position: absolute;
|
||||
width: 163rpx;
|
||||
height: 183rpx;
|
||||
top: 50rpx;
|
||||
right: 0rpx;
|
||||
background: #F7F8FA;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.cv-avatar-placeholder {
|
||||
color: #bbb;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cv-avatar-img {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.cv-purpose-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 36rpx;
|
||||
/* 不设置gap的列间距,水平方向用margin控制 */
|
||||
}
|
||||
|
||||
.cv-purpose-btn {
|
||||
width: calc((100% - 58rpx) / 3);
|
||||
margin-right: 29rpx;
|
||||
margin-bottom: 29rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 18rpx 0;
|
||||
text-align: center;
|
||||
background: #EBF5FF;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
}
|
||||
|
||||
.cv-purpose-btn:nth-child(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.cv-purpose-btn.active {
|
||||
background: #007CFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.cv-room-select {
|
||||
width: 435rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #808080;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 24rpx;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.cv-arrow {
|
||||
font-size: 32rpx;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.cv-time-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 23rpx;
|
||||
margin-top: 32rpx;
|
||||
}
|
||||
|
||||
.cv-time-btn {
|
||||
width: 302rpx;
|
||||
height: 73rpx;
|
||||
text-align: center;
|
||||
background: #EBF5FF;
|
||||
border-radius: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
display: flex;
|
||||
/* 新增 */
|
||||
align-items: center;
|
||||
/* 垂直居中 */
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cv-time-btn.active {
|
||||
background: #007CFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.cv-parking-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
|
||||
.cv-radio-label {
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 30rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
.cv-radio-label2 {
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 30rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cv-radio-custom {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
border-radius: 50%;
|
||||
border: 1rpx solid #007CFF;
|
||||
background: #fff;
|
||||
margin-right: 12rpx;
|
||||
box-sizing: border-box;
|
||||
transition: background 0.2s, border 0.2s;
|
||||
}
|
||||
|
||||
.cv-radio-custom.checked {
|
||||
background: #007CFF;
|
||||
border: 1rpx solid #007CFF;
|
||||
}
|
||||
|
||||
.cv-parking-count {
|
||||
margin-left: 24rpx;
|
||||
font-size: 24rpx;
|
||||
background: #EBF5FF;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 18rpx;
|
||||
height: 54rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.cv-parking-num {
|
||||
color: #007CFF;
|
||||
}
|
||||
.cv-parking-total {
|
||||
color: #0B0B0B;
|
||||
}
|
||||
|
||||
.cv-submit-btn {
|
||||
width: 90vw;
|
||||
height: 90rpx;
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
border: none;
|
||||
border-radius: 45rpx;
|
||||
margin: 80rpx auto 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
</style>
|
460
pages/sys/user/myVisitor/myVisitor.vue
Normal file
@@ -0,0 +1,460 @@
|
||||
<template>
|
||||
<view class="visitor-container">
|
||||
<!-- tab栏 -->
|
||||
<view class="visitor-tabs">
|
||||
<view v-for="(tab, idx) in tabs" :key="idx" :class="['visitor-tab', {active: idx === activeTab}]"
|
||||
@click="changeTab(idx)">
|
||||
{{ tab }}
|
||||
<view v-if="idx === activeTab" class="tab-underline"></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 列表区 -->
|
||||
<view class="visitor-list">
|
||||
<view v-for="(item, idx) in list" :key="idx" class="visitor-card" @click="showVisitorDetail(item)">
|
||||
<view class="card-row">
|
||||
<view class="card-type">{{ item.type }}</view>
|
||||
<view class="card-status" :class="item.statusClass">{{ item.status }}</view>
|
||||
</view>
|
||||
<view class="card-info">{{ item.name }}
|
||||
<text class="card-phone">{{ item.phone }}</text>
|
||||
<text class="card-divider"></text>
|
||||
<text class="card-address">{{ item.address }}</text>
|
||||
</view>
|
||||
<view class="card-time">{{ item.time }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<button class="visitor-btn-fixed" @click="goCreateVisitor">访客邀约</button>
|
||||
<view v-if="showDetail" class="visitor-detail-mask" @click.self="closeVisitorDetail">
|
||||
<view class="visitor-detail-dialog">
|
||||
<view class="visitor-detail-title-row">
|
||||
<text class="visitor-detail-title">访客详情</text>
|
||||
<image src="/static/ic_close_01.png" class="visitor-detail-close" @click="closeVisitorDetail" />
|
||||
</view>
|
||||
<view class="visitor-detail-info">
|
||||
<view>{{ detailData.name }} {{ detailData.phone }}</view>
|
||||
<view>{{ detailData.idCard || '5021119740208****' }}</view>
|
||||
<view>车牌号:{{ detailData.carNumber || '渝A·H1455' }}</view>
|
||||
<view>来访时间:{{ detailData.time }}</view>
|
||||
<view>访问地址:{{ detailData.address || '服务中心1栋8楼6871' }}</view>
|
||||
<image :src="detailData.statusClass === 'orange' ? '/static/ic_my_visitor_01.png' : '/static/ic_my_visitor_02.png'" class="visitor-detail-status-img" />
|
||||
</view>
|
||||
<button class="visitor-detail-btn">修改</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tabs: ['我的预约', '我的邀约', '全部记录'],
|
||||
activeTab: 1,
|
||||
tabData: [
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
], // 每个tab的数据
|
||||
tabLoaded: [false, false, false], // 每个tab是否已加载
|
||||
loading: false,
|
||||
showDetail: false,
|
||||
detailData: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
list() {
|
||||
return this.tabData[this.activeTab];
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadTabData(this.activeTab); // 初始化加载当前tab数据
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
goCreateVisitor() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/sys/user/myVisitor/creatVisitor'
|
||||
});
|
||||
},
|
||||
|
||||
async changeTab(idx) {
|
||||
this.activeTab = idx;
|
||||
if (!this.tabLoaded[idx]) {
|
||||
await this.loadTabData(idx);
|
||||
}
|
||||
},
|
||||
async loadTabData(idx) {
|
||||
this.loading = true;
|
||||
// 模拟接口请求,不同tab返回不同mock数据
|
||||
let data = [];
|
||||
if (idx === 0) {
|
||||
data = [{
|
||||
type: '商务合作',
|
||||
status: '待处理',
|
||||
statusClass: 'orange',
|
||||
name: '张小晓',
|
||||
phone: '18725468789',
|
||||
address: '8栋2楼309',
|
||||
time: '2025-07-06 15:28:16'
|
||||
},
|
||||
{
|
||||
type: '送货上门',
|
||||
status: '已到访',
|
||||
statusClass: 'green',
|
||||
name: '张小晓',
|
||||
phone: '18725468789',
|
||||
address: '8栋2楼309',
|
||||
time: '2025-07-06 15:28:16'
|
||||
},
|
||||
{
|
||||
type: '送货上门',
|
||||
status: '未到访',
|
||||
statusClass: 'green',
|
||||
name: '张小晓',
|
||||
phone: '18725468789',
|
||||
address: '8栋2楼309',
|
||||
time: '2025-07-06 15:28:16'
|
||||
},
|
||||
{ type: '商务合作', status: '待处理', statusClass: 'orange', name: '刘小备', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '送货上门', status: '已到访', statusClass: 'green', name: '关小羽', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '送货上门', status: '未到访', statusClass: 'green', name: '张小飞', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '商务合作', status: '待处理', statusClass: 'orange', name: '曹小操', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '送货上门', status: '已到访', statusClass: 'green', name: '孙小权', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '送货上门', status: '未到访', statusClass: 'green', name: '周小瑜', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' }
|
||||
];
|
||||
} else if (idx === 1) {
|
||||
data = [{
|
||||
type: '商务合作',
|
||||
status: '待处理',
|
||||
statusClass: 'orange',
|
||||
name: '李明',
|
||||
phone: '13812345678',
|
||||
address: '5栋1楼101',
|
||||
time: '2025-07-07 10:00:00'
|
||||
},
|
||||
{
|
||||
type: '送货上门',
|
||||
status: '已到访',
|
||||
statusClass: 'green',
|
||||
name: '王五',
|
||||
phone: '13987654321',
|
||||
address: '6栋3楼202',
|
||||
time: '2025-07-07 11:00:00'
|
||||
},
|
||||
{ type: '商务合作', status: '待处理', statusClass: 'orange', name: '赵六', phone: '13812345678', address: '5栋1楼101', time: '2025-07-07 10:00:00' },
|
||||
{ type: '送货上门', status: '已到访', statusClass: 'green', name: '钱七', phone: '13987654321', address: '6栋3楼202', time: '2025-07-07 11:00:00' },
|
||||
{ type: '商务合作', status: '待处理', statusClass: 'orange', name: '孙八', phone: '13812345678', address: '5栋1楼101', time: '2025-07-07 10:00:00' },
|
||||
{ type: '送货上门', status: '已到访', statusClass: 'green', name: '周九', phone: '13987654321', address: '6栋3楼202', time: '2025-07-07 11:00:00' }
|
||||
];
|
||||
} else {
|
||||
data = [{
|
||||
type: '商务合作',
|
||||
status: '已结束',
|
||||
statusClass: 'gray',
|
||||
name: '张小晓',
|
||||
phone: '18725468789',
|
||||
address: '8栋2楼309',
|
||||
time: '2025-07-06 15:28:16'
|
||||
},
|
||||
{
|
||||
type: '送货上门',
|
||||
status: '已结束',
|
||||
statusClass: 'gray',
|
||||
name: '李明',
|
||||
phone: '13812345678',
|
||||
address: '5栋1楼101',
|
||||
time: '2025-07-07 10:00:00'
|
||||
},
|
||||
{
|
||||
type: '送货上门',
|
||||
status: '已结束',
|
||||
statusClass: 'gray',
|
||||
name: '王五',
|
||||
phone: '13987654321',
|
||||
address: '6栋3楼202',
|
||||
time: '2025-07-07 11:00:00'
|
||||
},
|
||||
{ type: '商务合作', status: '已结束', statusClass: 'gray', name: '张小晓', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '送货上门', status: '已结束', statusClass: 'gray', name: '李明', phone: '13812345678', address: '5栋1楼101', time: '2025-07-07 10:00:00' },
|
||||
{ type: '送货上门', status: '已结束', statusClass: 'gray', name: '王五', phone: '13987654321', address: '6栋3楼202', time: '2025-07-07 11:00:00' },
|
||||
{ type: '商务合作', status: '已结束', statusClass: 'gray', name: '张小晓', phone: '18725468789', address: '8栋2楼309', time: '2025-07-06 15:28:16' },
|
||||
{ type: '送货上门', status: '已结束', statusClass: 'gray', name: '李明', phone: '13812345678', address: '5栋1楼101', time: '2025-07-07 10:00:00' },
|
||||
{ type: '送货上门', status: '已结束', statusClass: 'gray', name: '王五', phone: '13987654321', address: '6栋3楼202', time: '2025-07-07 11:00:00' }
|
||||
];
|
||||
}
|
||||
// 模拟网络延迟
|
||||
await new Promise(res => setTimeout(res, 300));
|
||||
this.$set(this.tabData, idx, data);
|
||||
this.$set(this.tabLoaded, idx, true);
|
||||
this.loading = false;
|
||||
},
|
||||
showVisitorDetail(item) {
|
||||
this.detailData = item;
|
||||
this.showDetail = true;
|
||||
},
|
||||
closeVisitorDetail() {
|
||||
this.showDetail = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.visitor-container {
|
||||
height: 100vh;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.visitor-navbar {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
flex-shrink: 0; /* 防止被压缩 */
|
||||
}
|
||||
|
||||
.visitor-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.visitor-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.visitor-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
background: #fff;
|
||||
height: 80rpx;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
flex-shrink: 0; /* 防止被压缩 */
|
||||
}
|
||||
|
||||
.visitor-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 30rpx;
|
||||
color: #888;
|
||||
position: relative;
|
||||
font-weight: 500;
|
||||
padding: 0 0 10rpx 0;
|
||||
/* tab点击事件 */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.visitor-tab.active {
|
||||
color: #2186FF;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tab-underline {
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
background: #2186FF;
|
||||
border-radius: 3rpx;
|
||||
margin: 0 auto;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.visitor-list {
|
||||
margin: 25rpx 0 0 0;
|
||||
padding: 0 35rpx;
|
||||
flex: 1; /* 占据所有剩余空间 */
|
||||
overflow-y: auto; /* 内容超出时,开启垂直滚动 */
|
||||
padding-bottom: 200rpx; /* 为底部按钮留出空间 */
|
||||
}
|
||||
|
||||
.visitor-card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
padding: 20rpx 40rpx 70rpx 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
|
||||
.card-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.card-type {
|
||||
font-weight: 600;
|
||||
font-size: 26rpx;
|
||||
padding: 10rpx 45rpx 10rpx 12rpx;
|
||||
border-radius: 15rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(90deg, #007CFF 0%, #FFFFFF 100%);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.card-status {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.card-status.orange {
|
||||
color: #F3831F;
|
||||
}
|
||||
|
||||
.card-status.green {
|
||||
color: #07C78E;
|
||||
}
|
||||
|
||||
.card-status.gray {
|
||||
color: #8F8F8F;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-phone {
|
||||
margin: 0 8rpx 0 8rpx;
|
||||
}
|
||||
|
||||
.card-divider {
|
||||
width: 1rpx;
|
||||
height: 40rpx;
|
||||
background: #DCDCDC;
|
||||
display: inline-block;
|
||||
margin: 0 12rpx;
|
||||
vertical-align: middle;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.card-address {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.card-time {
|
||||
font-size: 28rpx;
|
||||
color: #626262;
|
||||
}
|
||||
|
||||
.visitor-btn {
|
||||
width: 90vw;
|
||||
height: 80rpx;
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin: 60rpx auto 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.visitor-btn-fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100rpx;
|
||||
margin: 0 auto;
|
||||
width: 90vw;
|
||||
height: 80rpx;
|
||||
background: #0090FF;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.visitor-detail-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.visitor-detail-dialog {
|
||||
width: 66vw;
|
||||
background: #fff;
|
||||
border-radius: 36rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.12);
|
||||
padding: 48rpx 36rpx 36rpx 36rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.visitor-detail-title-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 52rpx;
|
||||
}
|
||||
.visitor-detail-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
.visitor-detail-close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
}
|
||||
.visitor-detail-info {
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
margin-bottom: 80rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 28rpx;
|
||||
position: relative;
|
||||
}
|
||||
.visitor-detail-status-img {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -40rpx;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
.visitor-detail-btn {
|
||||
width: 320rpx;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, #0090FF 0%, #2E9FFF 100%);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin-bottom: 30rpx;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.18);
|
||||
}
|
||||
</style>
|
343
pages/sys/user/myVisitor/visitorInfo.vue
Normal file
@@ -0,0 +1,343 @@
|
||||
<template>
|
||||
<view class="vi-container">
|
||||
<!-- 顶部 -->
|
||||
<view class="vi-navbar">
|
||||
<image src="/static/ic_back.png" class="vi-back" @click="goBack" />
|
||||
<text class="vi-title">预约申请</text>
|
||||
</view>
|
||||
<!-- 访客信息 -->
|
||||
<view class="vi-section info">
|
||||
<view class="vi-section-title">访客信息</view>
|
||||
<view class="vi-avatar-box">
|
||||
<view class="vi-avatar-placeholder">人脸照片</view>
|
||||
</view>
|
||||
<view class="vi-input-name">张桂花</view>
|
||||
<view class="vi-input-phone">13254789579</view>
|
||||
<view class="vi-input">5021119740214****</view>
|
||||
</view>
|
||||
<!-- 选择来访目的 -->
|
||||
<view class="vi-section">
|
||||
<view class="vi-section-title">选择来访目的</view>
|
||||
<view class="vi-purpose-list">
|
||||
<view class="vi-purpose-btn-active">园区参观</view>
|
||||
<view class="vi-purpose-btn">综合服务中心1栋8023</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 来访时间 -->
|
||||
<view class="vi-section">
|
||||
<view class="vi-section-title">来访时间</view>
|
||||
<view class="vi-time-btn">今天(2025-07-04)</view>
|
||||
</view>
|
||||
<!-- 是否预约车位 -->
|
||||
<view class="vi-section">
|
||||
<view class="vi-parking-row">
|
||||
<view class="vi-section-title2">是否预约车位</view>
|
||||
<view class="vi-checkbox-label">
|
||||
<view class="vi-checkbox checked"></view>
|
||||
<text>是</text>
|
||||
</view>
|
||||
<view class="vi-checkbox-label">
|
||||
<view class="vi-checkbox"></view>
|
||||
<text>否</text>
|
||||
</view>
|
||||
<text class="vi-parking-count">
|
||||
<text class="vi-parking-num">50</text><text class="vi-parking-total">/100</text>
|
||||
</text>
|
||||
</view>
|
||||
<view class="vi-car-input">渝A-V1254</view>
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<button class="vi-submit-btn">同意</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vi-container {
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.vi-navbar {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.vi-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.vi-title {
|
||||
font-size: 36rpx;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.vi-section {
|
||||
margin: 36rpx 56rpx 0 56rpx;
|
||||
}
|
||||
|
||||
.vi-section-title {
|
||||
font-size: 32rpx;
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
margin-bottom: 23rpx;
|
||||
}
|
||||
|
||||
|
||||
.vi-section-title2 {
|
||||
font-size: 32rpx;
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.vi-info-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.vi-inputs {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18rpx;
|
||||
}
|
||||
|
||||
.vi-input-name,
|
||||
.vi-input-phone,
|
||||
.vi-input {
|
||||
width: 233rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vi-avatar-box {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
background: #F7F8FA;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.vi-avatar-placeholder {
|
||||
color: #bbb;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vi-purpose-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 29rpx;
|
||||
margin-top: 36rpx;
|
||||
}
|
||||
|
||||
.vi-purpose-btn {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 18rpx 0;
|
||||
text-align: center;
|
||||
background: #EBF5FF;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
}
|
||||
|
||||
.vi-purpose-btn-active {
|
||||
width: 193rpx;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 18rpx 0;
|
||||
text-align: center;
|
||||
background: #007CFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.vi-time-btn {
|
||||
width: 302rpx;
|
||||
height: 73rpx;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
background: #EBF5FF;
|
||||
border-radius: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.vi-parking-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.vi-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
color: #0B0B0B;
|
||||
margin-left: 30rpx;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vi-checkbox {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
border-radius: 50%;
|
||||
border: 1rpx solid #007CFF;
|
||||
background: #fff;
|
||||
margin-right: 12rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vi-checkbox.checked {
|
||||
background: #007CFF;
|
||||
border: 1rpx solid #007CFF;
|
||||
}
|
||||
|
||||
.vi-parking-count {
|
||||
margin-left: 24rpx;
|
||||
font-size: 24rpx;
|
||||
background: #EBF5FF;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 18rpx;
|
||||
height: 54rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vi-parking-num {
|
||||
color: #007CFF;
|
||||
}
|
||||
|
||||
.vi-parking-total {
|
||||
color: #0B0B0B;
|
||||
}
|
||||
|
||||
.vi-car-input {
|
||||
width: 435rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-top: 29rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vi-submit-btn {
|
||||
width: 90vw;
|
||||
height: 90rpx;
|
||||
background: linear-gradient(90deg, #0090FF 0%, #2E9FFF 100%);
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
border: none;
|
||||
border-radius: 45rpx;
|
||||
margin: 80rpx auto 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.info {
|
||||
position: relative;
|
||||
margin: 36rpx 56rpx 0 56rpx;
|
||||
}
|
||||
|
||||
.vi-avatar-box {
|
||||
position: absolute;
|
||||
width: 163rpx;
|
||||
height: 183rpx;
|
||||
top: 50rpx;
|
||||
right: 0rpx;
|
||||
background: #F7F8FA;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.vi-avatar-placeholder {
|
||||
color: #bbb;
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vi-input-name {
|
||||
width: 233rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
margin-top: 23rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vi-input-phone {
|
||||
width: 363rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.vi-input {
|
||||
width: 435rpx;
|
||||
height: 73rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #222;
|
||||
padding: 0 24rpx;
|
||||
margin-bottom: 29rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
@@ -69,7 +69,7 @@ page {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/deep/ .u-cell-title {
|
||||
::v-deep .u-cell-title {
|
||||
padding: 25rpx 30rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
87
pages/sys/user/serviceCenter/questionDetail.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<view class="detail-container">
|
||||
<!-- 可滚动内容区 -->
|
||||
<view class="scroll-content">
|
||||
<!-- 问题标题 -->
|
||||
<view class="question-title">
|
||||
包月停车、临时停车的办理流程及收费标准
|
||||
<view class="title-underline"></view>
|
||||
</view>
|
||||
<!-- 内容区 -->
|
||||
<view class="question-content">
|
||||
<view class="question-desc">
|
||||
您好:本项目只有8组团为包月停车,办理流程为:业主携带身份证至物业客户中心前台办理,租户带租赁合同和身份证到前台办理即可;5,6,7,9,10,11组团无包月停车,无需办理包月停车手续;临时停车无需办理。5,6组团为私家车位,无需收费。8组团包月停车的收费标准为:500元/8组团临时停车的收费标准为:小区内9,10,11组团临时停车的收费标准为:二轮车:每小时1元,12小时内5元/次,24小时内10元/次;小型车:每小时3元,12小时内10元/次,24小时内20元/次;大型车:每小时4元,12小时内15元/次,24小时内25元/次
|
||||
</view>
|
||||
<image src="/static/ic_q_d_01.png" class="question-img" mode="widthFix" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.detail-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
.detail-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
.scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
.question-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
margin: 40rpx 32rpx 0 64rpx;
|
||||
position: relative;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.title-underline {
|
||||
width: 120rpx;
|
||||
height: 6rpx;
|
||||
background: #3B8BFF;
|
||||
border-radius: 3rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
.question-content {
|
||||
margin: 34rpx 24rpx 0 24rpx;
|
||||
background: #EDF6FF;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx dashed #bfc8d6;
|
||||
padding: 32rpx 24rpx 24rpx 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.question-desc {
|
||||
font-size: 28rpx;
|
||||
color: #4A4A4A;
|
||||
line-height: 1.8;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.question-img {
|
||||
width: 100%;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
</style>
|
283
pages/sys/user/serviceCenter/serviceCenter.vue
Normal file
@@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<view class="service-container">
|
||||
<!-- 固定顶部区域 -->
|
||||
<view class="fixed-header">
|
||||
<!-- 搜索框 -->
|
||||
<view class="service-search">
|
||||
<image src="/static/ic_search_gray.png" class="search-icon" />
|
||||
<input class="search-input" placeholder="请输入关键词 例 停车" />
|
||||
</view>
|
||||
<!-- 公告banner -->
|
||||
<view class="service-banner">
|
||||
<image src="/static/ic_s_c_01.png" class="banner-img" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 可滚动内容区 -->
|
||||
<view class="scroll-content">
|
||||
<!-- 常见问题 -->
|
||||
<view class="faq-title">常见问题</view>
|
||||
<view class="faq-list">
|
||||
<view class="faq-item" v-for="(item, idx) in faqList" :key="idx" @click="goDetail(idx)">
|
||||
<text class="faq-text">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="faq-end">- 到底了 -</view>
|
||||
<!-- 底部按钮 -->
|
||||
<button class="service-btn" @click="showDialog = true">电话咨询</button>
|
||||
</view>
|
||||
<!-- 弹窗 -->
|
||||
<view v-if="showDialog" class="dialog-mask" @click="showDialog = false">
|
||||
<view class="dialog-box">
|
||||
<image src="/static/ic_s_c_02.png" class="dialog-bg" mode="widthFix" />
|
||||
<view class="dialog-content">
|
||||
<view class="dialog-phone">023—950888</view>
|
||||
<button class="dialog-call-btn" @click.stop="callPhone">拨打电话</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
faqList: [
|
||||
'如何开取物业费发票,需要携带哪些资料?需要多...',
|
||||
'提交报修后一般多久会处理?',
|
||||
'生活服务优惠券怎么领取',
|
||||
'如何进行认证',
|
||||
'工程服务收费标准',
|
||||
'哪些时段可以进行施工装修',
|
||||
'包月停车、临时停车的办理流程及收费标准',
|
||||
'开锁的联系方式',
|
||||
'物业服务电话/投诉电话是多少',
|
||||
'电费查询及收费标准'
|
||||
],
|
||||
showDialog: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
callPhone() {
|
||||
this.showDialog = false;
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: '023950888'
|
||||
});
|
||||
},
|
||||
goDetail(idx) {
|
||||
uni.navigateTo({ url: '/pages/sys/user/serviceCenter/questionDetail' });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.service-container {
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.fixed-header {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.scroll-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.service-navbar {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.service-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.service-title {
|
||||
font-size: 36rpx;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.service-search {
|
||||
width: 85vw;
|
||||
background: rgba(225, 225, 225, 0.29);
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24rpx;
|
||||
height: 64rpx;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 28rpx;
|
||||
flex: 1;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.service-banner {
|
||||
margin: 32rpx 32rpx 0 32rpx;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
height: 180rpx;
|
||||
}
|
||||
|
||||
.banner-btn {
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
bottom: 18rpx;
|
||||
background: #fff;
|
||||
color: #0090FF;
|
||||
font-size: 22rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 6rpx 24rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 144, 255, 0.08);
|
||||
}
|
||||
|
||||
.faq-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #222;
|
||||
margin: 40rpx 0 18rpx 32rpx;
|
||||
}
|
||||
|
||||
.faq-list {
|
||||
background: #fff;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
.faq-item {
|
||||
padding: 0 32rpx;
|
||||
height: 64rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f7f7f7;
|
||||
}
|
||||
|
||||
.faq-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.faq-text {
|
||||
font-size: 28rpx;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.faq-end {
|
||||
text-align: center;
|
||||
color: #bbb;
|
||||
font-size: 26rpx;
|
||||
margin: 32rpx 0 0 0;
|
||||
}
|
||||
|
||||
.service-btn {
|
||||
width: 90vw;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, #2e6cf6 0%, #0090FF 100%);
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 40rpx;
|
||||
margin: 60rpx auto 0 auto;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 144, 255, 0.12);
|
||||
}
|
||||
|
||||
.dialog-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dialog-box {
|
||||
width: 476rpx;
|
||||
height: 552rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dialog-bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
border-radius: 28rpx;
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.dialog-phone {
|
||||
margin-top: 180rpx;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 38rpx;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
.dialog-call-btn {
|
||||
width: 90%;
|
||||
height: 80rpx;
|
||||
background: linear-gradient(90deg, #FFD600 0%, #FFB800 100%);
|
||||
color: #222;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
border-radius: 20rpx;
|
||||
margin: 40rpx auto 0 auto;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 184, 0, 0.12);
|
||||
}
|
||||
</style>
|
@@ -72,7 +72,7 @@ page {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/deep/ .u-cell-title {
|
||||
::v-deep .u-cell-title {
|
||||
padding: 25rpx 30rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
443
pages/sys/workbench/oa/oa.vue
Normal file
@@ -0,0 +1,443 @@
|
||||
<template>
|
||||
<view class="oa-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="oa-navbar">
|
||||
<image src="/static/ic_back.png" class="oa-back" @click="goBack" />
|
||||
<text class="oa-title">申批中心</text>
|
||||
</view>
|
||||
<!-- 搜索框 -->
|
||||
<view class="oa-search">
|
||||
<view class="search-box">
|
||||
<image src="/static/ic_search_gray.png" class="search-icon" />
|
||||
<text class="search-placeholder">申批名称、内容、发起人、编号</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- tab栏 -->
|
||||
<view class="oa-tabs">
|
||||
<view v-for="(tab, idx) in tabs" :key="idx" :class="['oa-tab', {active: idx === activeTab}]"
|
||||
@click="changeTab(idx)">
|
||||
{{ tab }}
|
||||
<view v-if="idx === activeTab" class="tab-underline"></view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 列表区 -->
|
||||
<view class="oa-list">
|
||||
<view v-for="(item, idx) in list" :key="idx" class="oa-card" :class="{'special-leave': item.status === '已通过'}" @click="goToDetail(item)">
|
||||
<view class="card-row">
|
||||
<view class="card-type">{{ item.type }}</view>
|
||||
<view class="card-status-tag" :class="item.statusClass">{{ item.status }}</view>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<view class="card-leave-type">请假类型:<text class="card-leave-type">{{ item.leaveType }}</text></view>
|
||||
<view class="card-leave-type">
|
||||
<text>开始时间:{{ item.startTime }}</text>
|
||||
</view>
|
||||
<view class="card-leave-type">
|
||||
<text>结束时间:{{ item.endTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer">
|
||||
<view class="card-user">
|
||||
<view class="user-avatar" :style="{backgroundColor: item.avatarColor}">{{ item.avatarText }}</view>
|
||||
<text class="user-name">{{ item.userName }}</text>
|
||||
</view>
|
||||
<text class="card-datetime">{{ item.dateTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tabs: ['待办', '已办', '已发起'],
|
||||
activeTab: 2, // 默认选中已发起
|
||||
tabData: [
|
||||
[], // 待办
|
||||
[], // 已办
|
||||
[] // 已发起
|
||||
],
|
||||
tabLoaded: [false, false, false], // 每个tab是否已加载
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
list() {
|
||||
return this.tabData[this.activeTab];
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadTabData(this.activeTab); // 初始化加载当前tab数据
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
// 跳转到详情页
|
||||
goToDetail(item) {
|
||||
uni.navigateTo({
|
||||
url: './oaDetail'
|
||||
});
|
||||
},
|
||||
async changeTab(idx) {
|
||||
this.activeTab = idx;
|
||||
if (!this.tabLoaded[idx]) {
|
||||
await this.loadTabData(idx);
|
||||
}
|
||||
},
|
||||
async loadTabData(idx) {
|
||||
this.loading = true;
|
||||
// 模拟接口请求,不同tab返回不同mock数据
|
||||
let data = [];
|
||||
if (idx === 0) { // 待办
|
||||
data = [
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待办',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
}
|
||||
];
|
||||
} else if (idx === 1) { // 已办
|
||||
data = [
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '已通过',
|
||||
statusClass: 'green',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
}
|
||||
];
|
||||
} else { // 已发起
|
||||
data = [
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '已通过',
|
||||
statusClass: 'green',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '请假',
|
||||
leaveType: '病假',
|
||||
status: '待审核',
|
||||
statusClass: 'orange',
|
||||
startTime: '2025-07-13',
|
||||
endTime: '2025-07-15',
|
||||
userName: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5',
|
||||
dateTime: '07-12 18:28:22'
|
||||
}
|
||||
];
|
||||
}
|
||||
// 模拟网络延迟
|
||||
await new Promise(res => setTimeout(res, 300));
|
||||
this.$set(this.tabData, idx, data);
|
||||
this.$set(this.tabLoaded, idx, true);
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.oa-container {
|
||||
height: 100vh;
|
||||
background: #f7f7f7;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.oa-navbar {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
padding-top: 40rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.oa-back {
|
||||
position: absolute;
|
||||
left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.oa-title {
|
||||
font-size: 36rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.oa-search {
|
||||
background: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
height: 70rpx;
|
||||
background: #F7F7F7;
|
||||
border-radius: 35rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.search-placeholder {
|
||||
color: #9A9A9A;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.oa-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
background: #fff;
|
||||
height: 80rpx;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.oa-tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
color: #737373;
|
||||
position: relative;
|
||||
padding: 0 0 10rpx 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.oa-tab.active {
|
||||
color: #007CFF;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tab-underline {
|
||||
width: 60rpx;
|
||||
height: 6rpx;
|
||||
background: #2186FF;
|
||||
border-radius: 3rpx;
|
||||
margin: 0 auto;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.oa-list {
|
||||
margin: 25rpx 0 0 0;
|
||||
padding: 0 35rpx;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.oa-card {
|
||||
background: #fff;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 26rpx;
|
||||
padding: 20rpx 20rpx 20rpx 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.card-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
|
||||
.card-type {
|
||||
width: 126rpx;
|
||||
height: 46rpx;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
padding-left: 10rpx;
|
||||
padding-top: 7rpx;
|
||||
border-radius: 15rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(90deg, #007CFF 0%, #FFFFFF 100%);
|
||||
}
|
||||
|
||||
.card-status-tag {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.card-status-tag.orange {
|
||||
color: #F27A0F;
|
||||
}
|
||||
|
||||
.card-status-tag.green {
|
||||
color: #0AC88F;
|
||||
}
|
||||
|
||||
.card-status-tag.gray {
|
||||
color: #8F8F8F;
|
||||
background-color: rgba(143, 143, 143, 0.1);
|
||||
border: 1px solid #8F8F8F;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 42rpx;
|
||||
}
|
||||
|
||||
.card-leave-type {
|
||||
color: #626262;
|
||||
font-size: 28;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.card-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 54rpx;
|
||||
height: 54rpx;
|
||||
border-radius: 27rpx;
|
||||
background-color: #688CFF;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 24rpx;
|
||||
color: #626262;
|
||||
}
|
||||
|
||||
.card-datetime {
|
||||
font-size: 24rpx;
|
||||
color: #626262;
|
||||
}
|
||||
|
||||
.special-leave {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.special-leave::after {
|
||||
content: '特批假';
|
||||
position: absolute;
|
||||
top: 10rpx;
|
||||
right: -50rpx;
|
||||
background-color: #F3831F;
|
||||
color: #fff;
|
||||
padding: 5rpx 60rpx;
|
||||
transform: rotate(45deg);
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
493
pages/sys/workbench/oa/oaDetail.vue
Normal file
@@ -0,0 +1,493 @@
|
||||
<template>
|
||||
<view class="detail-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="detail-navbar">
|
||||
<image src="/static/ic_back_white.webp" class="detail-back" @click="goBack" />
|
||||
<view class="detail-right">
|
||||
<image src="/static/ic_share_w.png" class="detail-scan" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 卡片容器 -->
|
||||
<view class="card-wrapper">
|
||||
<!-- 请假信息卡片 -->
|
||||
<view class="detail-card">
|
||||
<!-- 请假状态 -->
|
||||
<view class="leave-header">
|
||||
<view class="leave-type">请假</view>
|
||||
<view class="leave-status">已通过</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请人信息 -->
|
||||
<view class="applicant-info">
|
||||
<view class="applicant-avatar" style="background-color: #4B7BF5;">余</view>
|
||||
<view class="applicant-detail">
|
||||
<text class="applicant-name">余永乐</text>
|
||||
<text class="applicant-dept">数据开发及研发部</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提交时间 -->
|
||||
<view class="submit-time">提交时间:7月16日 18:36:44</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 其他卡片保持原结构 -->
|
||||
<view class="detail-card">
|
||||
<view class="detail-title">申批详情</view>
|
||||
|
||||
<view class="detail-item-vertical">
|
||||
<text class="detail-label-vertical">假期类型</text>
|
||||
<text class="detail-value-vertical">病假</text>
|
||||
</view>
|
||||
|
||||
<view class="detail-item-vertical">
|
||||
<text class="detail-label-vertical">开始时间</text>
|
||||
<text class="detail-value-vertical">2025-07-15</text>
|
||||
</view>
|
||||
|
||||
<view class="detail-item-vertical">
|
||||
<text class="detail-label-vertical">结束时间</text>
|
||||
<text class="detail-value-vertical">2025-07-17</text>
|
||||
</view>
|
||||
|
||||
<view class="detail-item-vertical">
|
||||
<text class="detail-label-vertical">时长</text>
|
||||
<text class="detail-value-vertical">2天</text>
|
||||
</view>
|
||||
|
||||
<view class="detail-item-vertical">
|
||||
<text class="detail-label-vertical">请假事由</text>
|
||||
<text class="detail-value-vertical">由于腿儿过大,需要到医院进行检查</text>
|
||||
</view>
|
||||
|
||||
<view class="detail-item-vertical">
|
||||
<text class="detail-label-vertical">附件</text>
|
||||
<view class="attachment">
|
||||
<view class="attachment-preview">
|
||||
<image src="/static/ic_attachment_preview.png" class="attachment-img" />
|
||||
</view>
|
||||
<view class="attachment-info">
|
||||
<text class="attachment-name">174568963.jpg</text>
|
||||
<text class="attachment-size">289.14 KB</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 审批记录卡片保持原结构 -->
|
||||
<view class="detail-card">
|
||||
<view class="detail-title">申批记录</view>
|
||||
|
||||
<view class="approval-item">
|
||||
<view class="approval-status">
|
||||
<view class="status-dot selected"></view>
|
||||
<view class="status-line" v-if="true"></view>
|
||||
</view>
|
||||
<view class="approval-content">
|
||||
<view class="approval-type">提交</view>
|
||||
<view class="approver-info">
|
||||
<view class="approver-avatar" style="background-color: #4B7BF5;">余</view>
|
||||
<text class="approver-name">余永乐</text>
|
||||
<text class="approval-result">已提交</text>
|
||||
</view>
|
||||
<text class="approval-time">07-12 18:28:22</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="approval-item">
|
||||
<view class="approval-status">
|
||||
<view class="status-dot selected"></view>
|
||||
<view class="status-line" v-if="true"></view>
|
||||
</view>
|
||||
<view class="approval-content">
|
||||
<view class="approval-type">审批</view>
|
||||
<view class="approver-info">
|
||||
<view class="approver-avatar" style="background-color: #F3831F;">张</view>
|
||||
<text class="approver-name">张桂花</text>
|
||||
<text class="approval-result">已同意</text>
|
||||
</view>
|
||||
<text class="approval-time">07-12 18:28:22</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="approval-item">
|
||||
<view class="approval-status">
|
||||
<view class="status-dot selected"></view>
|
||||
<view class="status-line" v-if="false"></view>
|
||||
</view>
|
||||
<view class="approval-content">
|
||||
<view class="approval-type">审批</view>
|
||||
<view class="approver-info">
|
||||
<view class="approver-avatar" style="background-color: #F3831F;">张</view>
|
||||
<text class="approver-name">张桂花</text>
|
||||
<text class="approval-result">已批准</text>
|
||||
</view>
|
||||
<text class="approval-time">07-12 18:28:22</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="approval-item">
|
||||
<view class="approval-status">
|
||||
<view class="status-dot"></view>
|
||||
</view>
|
||||
<view class="approval-content">
|
||||
<view class="approval-type">结束</view>
|
||||
<text class="approval-time">07-12 18:28:22</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* OA申批详情页面
|
||||
* @author lyc
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 详情数据
|
||||
detailData: {
|
||||
type: '请假',
|
||||
status: '已通过',
|
||||
leaveType: '病假',
|
||||
applicant: {
|
||||
name: '余永乐',
|
||||
dept: '数据开发及研发部',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5'
|
||||
},
|
||||
submitTime: '7月16日 18:36:44',
|
||||
startTime: '2025-07-15',
|
||||
endTime: '2025-07-17',
|
||||
duration: '2天',
|
||||
reason: '由于腿儿过大,需要到医院进行检查',
|
||||
attachment: {
|
||||
name: '174568963.jpg',
|
||||
size: '289.14 KB'
|
||||
},
|
||||
approvalRecords: [
|
||||
{
|
||||
type: '提交',
|
||||
approver: {
|
||||
name: '余永乐',
|
||||
avatarText: '余',
|
||||
avatarColor: '#4B7BF5'
|
||||
},
|
||||
result: '已提交',
|
||||
time: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '审批',
|
||||
approver: {
|
||||
name: '张桂花',
|
||||
avatarText: '张',
|
||||
avatarColor: '#F3831F'
|
||||
},
|
||||
result: '已同意',
|
||||
time: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '审批',
|
||||
approver: {
|
||||
name: '张桂花',
|
||||
avatarText: '张',
|
||||
avatarColor: '#F3831F'
|
||||
},
|
||||
result: '已批准',
|
||||
time: '07-12 18:28:22'
|
||||
},
|
||||
{
|
||||
type: '结束',
|
||||
time: '07-12 18:28:22'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
background-color: #f7f7f7;
|
||||
min-height: 100vh;
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
|
||||
/* 导航栏样式 */
|
||||
.detail-navbar {
|
||||
width: 100%;
|
||||
height: 372rpx;
|
||||
margin-bottom: -180rpx; /* 减少负边距避免过度覆盖 */
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
background: linear-gradient(180deg, #0A60ED 0%, #FFFFFF 100%);
|
||||
}
|
||||
|
||||
.detail-back {
|
||||
margin-left: 37rpx;
|
||||
width: 15rpx;
|
||||
height: 33rpx;
|
||||
}
|
||||
|
||||
.detail-right {
|
||||
margin-right: 37rpx;
|
||||
}
|
||||
|
||||
.detail-scan {
|
||||
width: 36rpx;
|
||||
height: 35rpx;
|
||||
}
|
||||
|
||||
/* 卡片通用样式 */
|
||||
.detail-card {
|
||||
z-index: 20; /* 提高层级确保显示在导航栏之上 */
|
||||
background-color: #fff;
|
||||
margin: 20rpx 30rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
border: 1px dashed #ddd;
|
||||
}
|
||||
|
||||
/* 请假信息卡片 */
|
||||
.leave-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.leave-type {
|
||||
font-weight: 600;
|
||||
font-size: 26rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #2186FF;
|
||||
background: rgba(33, 134, 255, 0.1);
|
||||
border: 1px solid #2186FF;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.leave-status {
|
||||
font-size: 26rpx;
|
||||
padding: 6rpx 20rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #07C78E;
|
||||
background-color: rgba(7, 199, 142, 0.1);
|
||||
border: 1px solid #07C78E;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.applicant-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.applicant-avatar {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 30rpx;
|
||||
background-color: #4B7BF5;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.applicant-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.applicant-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.applicant-dept {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.submit-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 申批详情 */
|
||||
.detail-title {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
width: 150rpx;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 垂直布局的申批详情 */
|
||||
.detail-item-vertical {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.detail-label-vertical {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.detail-value-vertical {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
/* 附件样式 */
|
||||
.attachment {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.attachment-preview {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.attachment-img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.attachment-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.attachment-name {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.attachment-size {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 审批记录 */
|
||||
.approval-item {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.approval-status {
|
||||
width: 30rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
border-radius: 10rpx;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.status-dot.selected {
|
||||
background-color: #2186FF;
|
||||
border-color: #2186FF;
|
||||
}
|
||||
|
||||
.status-line {
|
||||
width: 2rpx;
|
||||
flex: 1;
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.approval-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.approval-type {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.approver-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.approver-avatar {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 20rpx;
|
||||
background-color: #4B7BF5;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.approver-name {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.approval-result {
|
||||
font-size: 24rpx;
|
||||
color: #07C78E;
|
||||
}
|
||||
|
||||
.approval-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
257
pages/sys/workbench/workbench.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<template>
|
||||
<view class="workbench-container">
|
||||
<view class="workbench-header">
|
||||
<view class="workbench-topbg"></view>
|
||||
<!-- 顶部蓝色背景和搜索栏 -->
|
||||
<view class="workbench-search-row">
|
||||
<view class="search-bar">
|
||||
<image class="search-icon" src="/static/ic_search_gray.png"/>
|
||||
<input class="search-input" placeholder="搜索" />
|
||||
</view>
|
||||
<text class="search-btn">搜索</text>
|
||||
</view>
|
||||
|
||||
<!-- banner 区域 -->
|
||||
<view class="workbench-banner">
|
||||
<image class="banner-img" src="/static/workbench_banner.png" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 常用应用九宫格 -->
|
||||
<view class="workbench-grid">
|
||||
<view class="grid-item" v-for="(item, idx) in commonApps" :key="idx">
|
||||
<image :src="item.icon" class="grid-icon" />
|
||||
<text class="grid-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 全部应用 -->
|
||||
<view >
|
||||
<view class="all-apps-title">全部应用</view>
|
||||
<view class="all-apps-tabs">
|
||||
<text v-for="(tab, idx) in tabs" :key="idx" :class="['tab', {active: idx === activeTab}]"
|
||||
@click="activeTab = idx">{{ tab }}</text>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="workbench-grid">
|
||||
<view class="grid-item" v-for="(item, idx) in allApps[activeTab]" :key="idx">
|
||||
<image :src="item.icon" class="grid-icon" />
|
||||
<text class="grid-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Workbench',
|
||||
data() {
|
||||
return {
|
||||
commonApps: [
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '审批' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '假勤' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '工单' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '停车' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '保洁' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '邀约' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '会议' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '添加常用' }
|
||||
],
|
||||
tabs: ['最近使用', 'OA 管理', '敏捷开发', '协同办公'],
|
||||
activeTab: 0,
|
||||
allApps: [
|
||||
// 最近使用
|
||||
[
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '文档' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '表格' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: 'PPT' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '笔记' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '录音' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '云打印' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '智能门禁' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '易企秀H5' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '多维表格' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '问卷网' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '集客云' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '收票宝' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '图表' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '消息' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '沟通' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '' }
|
||||
],
|
||||
// OA 管理
|
||||
[
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '文档' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '表格' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: 'PPT' }
|
||||
],
|
||||
// 敏捷开发
|
||||
[
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '集客云' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '问卷网' }
|
||||
],
|
||||
// 协同办公
|
||||
[
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '笔记' },
|
||||
{ icon: 'https://picsum.photos/80/80?random=3', text: '沟通' }
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.workbench-container {
|
||||
min-height: 100vh;
|
||||
background: #fff;
|
||||
padding-bottom: 120rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.workbench-header {
|
||||
position: relative;
|
||||
height: 463rpx;
|
||||
width: 100vw;
|
||||
margin-bottom: -40rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.workbench-topbg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 463rpx;
|
||||
background-image: linear-gradient(to bottom, #075EED, #FFFFFF);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.workbench-search-row {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
padding: 80rpx 44rpx 0 34rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 30rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 56rpx;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
width: 27rpx;
|
||||
height: 27rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
border: none;
|
||||
font-size: 26rpx;
|
||||
flex: 1;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.workbench-banner {
|
||||
width: 92vw;
|
||||
height: 140rpx;
|
||||
margin: 0 auto 20rpx auto;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
height: 140rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.workbench-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding-left: 30rpx;
|
||||
padding-right: 30rpx;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.grid-icon {
|
||||
width: 98rpx;
|
||||
height: 98rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.grid-text {
|
||||
font-size: 24rpx;
|
||||
color: #1D1D1D;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
.all-apps-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
margin-bottom: 33rpx;
|
||||
margin-left: 35rpx;
|
||||
}
|
||||
|
||||
.all-apps-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 54rpx;
|
||||
padding-right: 54rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-right: 32rpx;
|
||||
padding-bottom: 6rpx;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #2e6cf6;
|
||||
border-bottom: 4rpx solid #2e6cf6;
|
||||
}
|
||||
|
||||
.all-apps-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 0 54rpx 0 54rpx;
|
||||
}
|
||||
.line{
|
||||
background: #DCDCDC;
|
||||
height: 2rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
</style>
|
BIN
static/ic_add_repair_01.png
Normal file
After Width: | Height: | Size: 399 B |
BIN
static/ic_arrow_gray.webp
Normal file
After Width: | Height: | Size: 218 B |
BIN
static/ic_back.png
Normal file
After Width: | Height: | Size: 813 B |
BIN
static/ic_back_white.webp
Normal file
After Width: | Height: | Size: 450 B |
BIN
static/ic_close_01.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
static/ic_evaluate_disselect.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/ic_evaluate_select.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
static/ic_i_c_01.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
static/ic_i_c_02.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
static/ic_i_c_03.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
static/ic_i_c_bg.png
Normal file
After Width: | Height: | Size: 631 KiB |
BIN
static/ic_login_agree.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/ic_login_code.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
static/ic_login_dis.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
static/ic_login_phone.png
Normal file
After Width: | Height: | Size: 847 B |
BIN
static/ic_login_topbg.png
Normal file
After Width: | Height: | Size: 522 KiB |
BIN
static/ic_main_home.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
static/ic_main_home_selected.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
static/ic_main_mine.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/ic_main_mine_selected.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
static/ic_main_work.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
static/ic_main_work_selected.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
static/ic_mine_check.png
Normal file
After Width: | Height: | Size: 1004 B |
BIN
static/ic_mine_head.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
static/ic_mine_info.png
Normal file
After Width: | Height: | Size: 848 B |
BIN
static/ic_mine_notice.png
Normal file
After Width: | Height: | Size: 816 B |
BIN
static/ic_mine_pay.png
Normal file
After Width: | Height: | Size: 545 B |
BIN
static/ic_mine_pwd.png
Normal file
After Width: | Height: | Size: 692 B |
BIN
static/ic_mine_repair.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/ic_mine_setting.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/ic_mine_setting2.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
static/ic_mine_topbg.png
Normal file
After Width: | Height: | Size: 356 KiB |
BIN
static/ic_mine_version.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/ic_mine_visitor.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
static/ic_msg.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
static/ic_msg_01.png
Normal file
After Width: | Height: | Size: 292 KiB |
BIN
static/ic_msg_empty.png
Normal file
After Width: | Height: | Size: 214 KiB |
BIN
static/ic_my_payment_01.png
Normal file
After Width: | Height: | Size: 947 KiB |
BIN
static/ic_my_payment_02.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
static/ic_my_repair_01.png
Normal file
After Width: | Height: | Size: 760 KiB |
BIN
static/ic_my_repair_02.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/ic_my_repair_03.png
Normal file
After Width: | Height: | Size: 650 B |
BIN
static/ic_my_visitor_01.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
static/ic_my_visitor_02.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
static/ic_payment_record_01.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
static/ic_repaired_01.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/ic_s_c_01.png
Normal file
After Width: | Height: | Size: 352 KiB |
BIN
static/ic_s_c_02.png
Normal file
After Width: | Height: | Size: 529 KiB |
BIN
static/ic_scan.png
Normal file
After Width: | Height: | Size: 543 B |
BIN
static/ic_search.png
Normal file
After Width: | Height: | Size: 962 B |
BIN
static/ic_search_gray.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
static/ic_share_w.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
static/ic_tq.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
static/ic_work_01.png
Normal file
After Width: | Height: | Size: 682 KiB |
BIN
static/logo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
144
utils/mediaSelector.README.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# 媒体选择器工具类 (MediaSelector)
|
||||
|
||||
这是一个用于在uni-app项目中选择本地图片和视频的工具类,提供了统一的接口和灵活的配置选项。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- 支持选择图片、视频或让用户选择图片/视频
|
||||
- 支持设置选择数量
|
||||
- 支持设置是否压缩
|
||||
- 支持图片裁剪
|
||||
- 支持设置视频最大时长
|
||||
- 支持设置使用的摄像头(前置/后置)
|
||||
- 支持设置允许的文件扩展名
|
||||
- 提供媒体预览功能
|
||||
|
||||
## 安装和使用
|
||||
|
||||
### 1. 导入工具类
|
||||
|
||||
```javascript
|
||||
import MediaSelector, { MediaType } from '@/utils/mediaSelector';
|
||||
```
|
||||
|
||||
### 2. 选择图片
|
||||
|
||||
```javascript
|
||||
// 选择最多9张图片
|
||||
const images = await MediaSelector.choose({
|
||||
type: MediaType.IMAGE,
|
||||
count: 9,
|
||||
compressed: true,
|
||||
crop: false
|
||||
});
|
||||
|
||||
console.log('选择的图片:', images);
|
||||
```
|
||||
|
||||
### 3. 选择视频
|
||||
|
||||
```javascript
|
||||
// 选择最多1个视频
|
||||
const videos = await MediaSelector.choose({
|
||||
type: MediaType.VIDEO,
|
||||
count: 1,
|
||||
compressed: true,
|
||||
videoMaxDuration: 60 // 最长60秒
|
||||
});
|
||||
|
||||
console.log('选择的视频:', videos);
|
||||
```
|
||||
|
||||
### 4. 选择图片或视频(用户可选择)
|
||||
|
||||
```javascript
|
||||
// 让用户选择图片或视频
|
||||
const media = await MediaSelector.choose({
|
||||
type: MediaType.BOTH,
|
||||
count: 5
|
||||
});
|
||||
|
||||
console.log('选择的媒体:', media);
|
||||
```
|
||||
|
||||
### 5. 预览媒体
|
||||
|
||||
```javascript
|
||||
// 预览媒体(自动判断类型)
|
||||
if (media.length > 0) {
|
||||
MediaSelector.preview(media[0].path, media[0].type);
|
||||
}
|
||||
```
|
||||
|
||||
## API 文档
|
||||
|
||||
### MediaType 枚举
|
||||
|
||||
```javascript
|
||||
export const MediaType = {
|
||||
IMAGE: 'image', // 图片
|
||||
VIDEO: 'video', // 视频
|
||||
BOTH: 'both' // 图片和视频
|
||||
};
|
||||
```
|
||||
|
||||
### MediaSelector.choose(options)
|
||||
|
||||
选择媒体文件(图片或视频)。
|
||||
|
||||
#### 参数
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| options.type | string | 'image' | 媒体类型,可选值:'image'、'video'、'both' |
|
||||
| options.count | number | 9 | 最大选择数量 |
|
||||
| options.imageExtensions | Array<string> | ['png', 'jpg', 'jpeg', 'gif', 'webp'] | 图片扩展名 |
|
||||
| options.videoExtensions | Array<string> | ['mp4', 'mov', '3gp', 'avi', 'rmvb', 'rm', 'flv', 'mkv'] | 视频扩展名 |
|
||||
| options.compressed | boolean | true | 是否压缩所选文件 |
|
||||
| options.crop | boolean | false | 是否裁剪(仅对图片有效) |
|
||||
| options.videoMaxDuration | number | 60 | 拍摄视频最长拍摄时间,单位秒 |
|
||||
| options.camera | string | 'back' | 使用的摄像头,可选值:'back'、'front' |
|
||||
|
||||
#### 返回值
|
||||
|
||||
返回一个Promise,解析为选择的媒体文件数组。每个媒体文件对象包含以下属性:
|
||||
|
||||
- **图片对象属性**:
|
||||
- path: 文件路径
|
||||
- size: 文件大小(字节)
|
||||
- name: 文件名
|
||||
- type: 媒体类型('image')
|
||||
- extension: 文件扩展名
|
||||
- createTime: 创建时间戳
|
||||
|
||||
- **视频对象属性**:
|
||||
- path: 文件路径
|
||||
- size: 文件大小(字节)
|
||||
- duration: 视频时长(秒)
|
||||
- width: 视频宽度
|
||||
- height: 视频高度
|
||||
- name: 文件名
|
||||
- type: 媒体类型('video')
|
||||
- extension: 文件扩展名
|
||||
- createTime: 创建时间戳
|
||||
|
||||
### MediaSelector.preview(path, type)
|
||||
|
||||
预览媒体文件。
|
||||
|
||||
#### 参数
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| path | string | - | 文件路径 |
|
||||
| type | string | 自动判断 | 媒体类型,可选值:'image'、'video',默认根据文件扩展名自动判断 |
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 由于uni.chooseVideo一次只能选择一个视频,当设置count>1时,工具类会引导用户多次选择。
|
||||
2. 视频预览功能需要一个视频播放页面,默认路径为`/pages/common/video-player`,如果您的项目中没有此页面,请自行创建或修改预览方法。
|
||||
3. 在某些平台上,部分功能可能受到限制,请根据实际情况调整使用方式。
|
||||
|
||||
## 示例代码
|
||||
|
||||
完整的使用示例请参考 `mediaSelector.example.js` 文件。
|
136
utils/mediaSelector.example.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 媒体选择器使用示例
|
||||
*/
|
||||
|
||||
// 导入媒体选择器工具类
|
||||
import MediaSelector, { MediaType } from './mediaSelector';
|
||||
|
||||
/**
|
||||
* 选择图片示例
|
||||
*/
|
||||
export async function chooseImagesExample() {
|
||||
try {
|
||||
// 选择最多9张图片
|
||||
const images = await MediaSelector.choose({
|
||||
type: MediaType.IMAGE,
|
||||
count: 9,
|
||||
compressed: true,
|
||||
crop: false
|
||||
});
|
||||
|
||||
console.log('选择的图片:', images);
|
||||
return images;
|
||||
} catch (error) {
|
||||
console.error('选择图片失败:', error);
|
||||
uni.showToast({
|
||||
title: '选择图片失败',
|
||||
icon: 'none'
|
||||
});
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择视频示例
|
||||
*/
|
||||
export async function chooseVideosExample() {
|
||||
try {
|
||||
// 选择最多1个视频
|
||||
const videos = await MediaSelector.choose({
|
||||
type: MediaType.VIDEO,
|
||||
count: 1,
|
||||
compressed: true,
|
||||
videoMaxDuration: 60 // 最长60秒
|
||||
});
|
||||
|
||||
console.log('选择的视频:', videos);
|
||||
return videos;
|
||||
} catch (error) {
|
||||
console.error('选择视频失败:', error);
|
||||
uni.showToast({
|
||||
title: '选择视频失败',
|
||||
icon: 'none'
|
||||
});
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择图片或视频示例(用户可选择)
|
||||
*/
|
||||
export async function chooseBothExample() {
|
||||
try {
|
||||
// 让用户选择图片或视频
|
||||
const media = await MediaSelector.choose({
|
||||
type: MediaType.BOTH,
|
||||
count: 5
|
||||
});
|
||||
|
||||
console.log('选择的媒体:', media);
|
||||
return media;
|
||||
} catch (error) {
|
||||
console.error('选择媒体失败:', error);
|
||||
uni.showToast({
|
||||
title: '选择媒体失败',
|
||||
icon: 'none'
|
||||
});
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览媒体示例
|
||||
* @param {Object} mediaItem 媒体项
|
||||
*/
|
||||
export function previewMediaExample(mediaItem) {
|
||||
if (!mediaItem || !mediaItem.path) {
|
||||
uni.showToast({
|
||||
title: '无效的媒体文件',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 预览媒体(自动判断类型)
|
||||
MediaSelector.preview(mediaItem.path, mediaItem.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在页面中使用的完整示例
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
mediaList: [] // 存储选择的媒体列表
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 选择图片
|
||||
async chooseImages() {
|
||||
const images = await chooseImagesExample();
|
||||
this.mediaList = [...this.mediaList, ...images];
|
||||
},
|
||||
|
||||
// 选择视频
|
||||
async chooseVideos() {
|
||||
const videos = await chooseVideosExample();
|
||||
this.mediaList = [...this.mediaList, ...videos];
|
||||
},
|
||||
|
||||
// 选择图片或视频
|
||||
async chooseBoth() {
|
||||
const media = await chooseBothExample();
|
||||
this.mediaList = [...this.mediaList, ...media];
|
||||
},
|
||||
|
||||
// 预览媒体
|
||||
previewMedia(item) {
|
||||
previewMediaExample(item);
|
||||
},
|
||||
|
||||
// 删除媒体
|
||||
deleteMedia(index) {
|
||||
this.mediaList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
328
utils/mediaSelector.js
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* 媒体选择器工具类
|
||||
* 用于选择本地图片和视频
|
||||
* 支持设置选择类型(图片、视频或两者)和选择数量
|
||||
*/
|
||||
|
||||
// 媒体类型枚举
|
||||
export const MediaType = {
|
||||
IMAGE: 'image',
|
||||
VIDEO: 'video',
|
||||
BOTH: 'both'
|
||||
};
|
||||
|
||||
/**
|
||||
* 媒体选择器类
|
||||
*/
|
||||
export default class MediaSelector {
|
||||
/**
|
||||
* 选择媒体文件(图片或视频)
|
||||
* @param {Object} options 选择配置项
|
||||
* @param {string} options.type 媒体类型,可选值:'image'、'video'、'both',默认为'image'
|
||||
* @param {number} options.count 最大选择数量,默认为9
|
||||
* @param {Array<string>} options.imageExtensions 图片扩展名,默认为['png', 'jpg', 'jpeg', 'gif', 'webp']
|
||||
* @param {Array<string>} options.videoExtensions 视频扩展名,默认为['mp4', 'mov', '3gp', 'avi', 'rmvb', 'rm', 'flv', 'mkv']
|
||||
* @param {boolean} options.compressed 是否压缩所选文件,默认为true
|
||||
* @param {boolean} options.crop 是否裁剪(仅对图片有效),默认为false
|
||||
* @param {number} options.videoMaxDuration 拍摄视频最长拍摄时间,单位秒,默认为60
|
||||
* @param {string} options.camera 使用的摄像头,可选值:'back'、'front',默认为'back'
|
||||
* @returns {Promise<Array>} 返回选择的媒体文件数组
|
||||
*/
|
||||
static async choose(options = {}) {
|
||||
const {
|
||||
type = MediaType.IMAGE,
|
||||
count = 9,
|
||||
imageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'webp'],
|
||||
videoExtensions = ['mp4', 'mov', '3gp', 'avi', 'rmvb', 'rm', 'flv', 'mkv'],
|
||||
compressed = true,
|
||||
crop = false,
|
||||
videoMaxDuration = 60,
|
||||
camera = 'back'
|
||||
} = options;
|
||||
|
||||
// 根据类型选择不同的媒体
|
||||
if (type === MediaType.IMAGE) {
|
||||
return this.chooseImages({ count, extensions: imageExtensions, compressed, crop, camera });
|
||||
} else if (type === MediaType.VIDEO) {
|
||||
return this.chooseVideos({ count, extensions: videoExtensions, compressed, maxDuration: videoMaxDuration, camera });
|
||||
} else if (type === MediaType.BOTH) {
|
||||
// 如果是两者都选,则先让用户选择类型
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.showActionSheet({
|
||||
itemList: ['选择图片', '选择视频'],
|
||||
success: async (res) => {
|
||||
try {
|
||||
if (res.tapIndex === 0) {
|
||||
// 选择图片
|
||||
const images = await this.chooseImages({ count, extensions: imageExtensions, compressed, crop, camera });
|
||||
resolve(images);
|
||||
} else {
|
||||
// 选择视频
|
||||
const videos = await this.chooseVideos({ count, extensions: videoExtensions, compressed, maxDuration: videoMaxDuration, camera });
|
||||
resolve(videos);
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
throw new Error('不支持的媒体类型');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择图片
|
||||
* @param {Object} options 选择图片的配置项
|
||||
* @returns {Promise<Array>} 返回选择的图片数组
|
||||
*/
|
||||
static chooseImages(options) {
|
||||
const { count = 9, extensions = ['png', 'jpg', 'jpeg', 'gif', 'webp'], compressed = true, crop = false, camera = 'back' } = options;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseImage({
|
||||
count,
|
||||
sizeType: compressed ? ['compressed'] : ['original'],
|
||||
sourceType: ['album', 'camera'],
|
||||
extension: extensions,
|
||||
crop: crop ? {
|
||||
quality: 100,
|
||||
width: 300,
|
||||
height: 300,
|
||||
resize: true
|
||||
} : false,
|
||||
camera,
|
||||
success: (res) => {
|
||||
// 处理返回的图片数据,统一格式
|
||||
const images = res.tempFiles.map(file => ({
|
||||
path: file.path,
|
||||
size: file.size,
|
||||
name: this.getFileName(file.path),
|
||||
type: 'image',
|
||||
extension: this.getFileExtension(file.path),
|
||||
createTime: new Date().getTime()
|
||||
}));
|
||||
resolve(images);
|
||||
},
|
||||
fail: (err) => {
|
||||
// 用户取消选择不报错
|
||||
if (err.errMsg.indexOf('cancel') !== -1) {
|
||||
resolve([]);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择视频
|
||||
* @param {Object} options 选择视频的配置项
|
||||
* @returns {Promise<Array>} 返回选择的视频数组
|
||||
*/
|
||||
static chooseVideos(options) {
|
||||
const { count = 1, extensions = ['mp4', 'mov', '3gp', 'avi', 'rmvb', 'rm', 'flv', 'mkv'], compressed = true, maxDuration = 60, camera = 'back' } = options;
|
||||
|
||||
// 由于uni.chooseVideo一次只能选择一个视频,如果count>1,需要多次选择
|
||||
if (count <= 1) {
|
||||
return this.chooseSingleVideo({ extensions, compressed, maxDuration, camera });
|
||||
} else {
|
||||
// 提示用户需要多次选择
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `您需要选择${count}个视频,将分${count}次选择`,
|
||||
confirmText: '开始选择',
|
||||
cancelText: '取消',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
const videos = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
// 显示当前选择进度
|
||||
uni.showLoading({
|
||||
title: `正在选择第${i + 1}/${count}个视频`,
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 选择单个视频
|
||||
const videoResult = await this.chooseSingleVideo({ extensions, compressed, maxDuration, camera });
|
||||
|
||||
// 隐藏加载提示
|
||||
uni.hideLoading();
|
||||
|
||||
// 如果用户取消了选择,则结束循环
|
||||
if (videoResult.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 添加到结果数组
|
||||
videos.push(...videoResult);
|
||||
|
||||
// 如果还没选完,询问是否继续
|
||||
if (i < count - 1) {
|
||||
const continueRes = await new Promise((resolveDialog) => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `已选择${videos.length}个视频,是否继续选择?`,
|
||||
confirmText: '继续',
|
||||
cancelText: '完成',
|
||||
success: (modalRes) => {
|
||||
resolveDialog(modalRes.confirm);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 如果用户选择不继续,则结束循环
|
||||
if (!continueRes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve(videos);
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
reject(error);
|
||||
}
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择单个视频
|
||||
* @param {Object} options 选择视频的配置项
|
||||
* @returns {Promise<Array>} 返回选择的视频数组
|
||||
*/
|
||||
static chooseSingleVideo(options) {
|
||||
const { extensions = ['mp4', 'mov', '3gp', 'avi', 'rmvb', 'rm', 'flv', 'mkv'], compressed = true, maxDuration = 60, camera = 'back' } = options;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.chooseVideo({
|
||||
sourceType: ['album', 'camera'],
|
||||
compressed,
|
||||
maxDuration,
|
||||
camera,
|
||||
extension: extensions,
|
||||
success: (res) => {
|
||||
// 处理返回的视频数据,统一格式
|
||||
const video = {
|
||||
path: res.tempFilePath,
|
||||
size: res.size,
|
||||
duration: res.duration,
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
name: this.getFileName(res.tempFilePath),
|
||||
type: 'video',
|
||||
extension: this.getFileExtension(res.tempFilePath),
|
||||
createTime: new Date().getTime()
|
||||
};
|
||||
resolve([video]);
|
||||
},
|
||||
fail: (err) => {
|
||||
// 用户取消选择不报错
|
||||
if (err.errMsg.indexOf('cancel') !== -1) {
|
||||
resolve([]);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名
|
||||
* @param {string} path 文件路径
|
||||
* @returns {string} 文件名
|
||||
*/
|
||||
static getFileName(path) {
|
||||
if (!path) return '';
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
* @param {string} path 文件路径
|
||||
* @returns {string} 文件扩展名
|
||||
*/
|
||||
static getFileExtension(path) {
|
||||
if (!path) return '';
|
||||
return path.substring(path.lastIndexOf('.') + 1).toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览媒体文件
|
||||
* @param {string} path 文件路径
|
||||
* @param {string} type 媒体类型,可选值:'image'、'video',默认根据文件扩展名自动判断
|
||||
*/
|
||||
static preview(path, type) {
|
||||
if (!path) return;
|
||||
|
||||
// 如果未指定类型,则根据文件扩展名判断
|
||||
if (!type) {
|
||||
const extension = this.getFileExtension(path);
|
||||
if (['png', 'jpg', 'jpeg', 'gif', 'webp'].includes(extension)) {
|
||||
type = MediaType.IMAGE;
|
||||
} else if (['mp4', 'mov', '3gp', 'avi', 'rmvb', 'rm', 'flv', 'mkv'].includes(extension)) {
|
||||
type = MediaType.VIDEO;
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '不支持的文件类型',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 根据类型预览
|
||||
if (type === MediaType.IMAGE) {
|
||||
uni.previewImage({
|
||||
urls: [path],
|
||||
current: path
|
||||
});
|
||||
} else if (type === MediaType.VIDEO) {
|
||||
// 视频预览
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/video-player?url=${encodeURIComponent(path)}`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用示例:
|
||||
*
|
||||
* // 导入
|
||||
* import MediaSelector, { MediaType } from '@/utils/mediaSelector';
|
||||
*
|
||||
* // 选择图片
|
||||
* const images = await MediaSelector.choose({ type: MediaType.IMAGE, count: 9 });
|
||||
* console.log('选择的图片:', images);
|
||||
*
|
||||
* // 选择视频
|
||||
* const videos = await MediaSelector.choose({ type: MediaType.VIDEO, count: 1 });
|
||||
* console.log('选择的视频:', videos);
|
||||
*
|
||||
* // 选择图片或视频(用户可选择)
|
||||
* const media = await MediaSelector.choose({ type: MediaType.BOTH, count: 5 });
|
||||
* console.log('选择的媒体:', media);
|
||||
*
|
||||
* // 预览媒体
|
||||
* if (media.length > 0) {
|
||||
* MediaSelector.preview(media[0].path, media[0].type);
|
||||
* }
|
||||
*/
|
@@ -8,7 +8,7 @@ module.exports = {
|
||||
disableHostCheck : true,
|
||||
proxy : {
|
||||
"/js" : {
|
||||
target : "http://192.168.0.104:8080",
|
||||
target : "http://tc.cqsznc.com:7080",
|
||||
// target : "https://demo.aidex.vip",
|
||||
changeOrigin : true,
|
||||
secure : false
|
||||
|