| | |
| | | |
| | | /unpackage/* |
| | | /node_modules/* |
| | | |
| | | /uni_modules/* |
| | | ###################################################################### |
| | | # Development Tools |
| | | |
| | |
| | | <p align="center"> |
| | | <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-43e3941654fa3054c9684bf53d1b1d356a1.png"> |
| | | </p> |
| | | <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v1.1.0</h1> |
| | | <h4 align="center">基于UniApp开发的轻量级移动端框架</h4> |
| | | <p align="center"> |
| | | <a href="https://gitee.com/y_project/RuoYi-App/stargazers"><img src="https://gitee.com/y_project/RuoYi-App/badge/star.svg?theme=dark"></a> |
| | | <a href="https://gitee.com/y_project/RuoYi-App"><img src="https://img.shields.io/badge/RuoYi-v1.1.0-brightgreen.svg"></a> |
| | | <a href="https://gitee.com/y_project/RuoYi-App/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> |
| | | </p> |
| | | # 若依任务调度移动应用 |
| | | |
| | | ## 平台简介 |
| | | ## 项目介绍 |
| | | 这是一个基于uni-app开发的任务调度移动应用,包含任务管理、消息通知、微信登录等功能。 |
| | | |
| | | RuoYi App 移动解决方案,采用uniapp框架,一份代码多终端适配,同时支持APP、小程序、H5!实现了与[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)、[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)完美对接的移动解决方案!目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。 |
| | | ## 功能模块 |
| | | 1. **首页** - 应用入口和概览 |
| | | 2. **任务** - 任务列表查看和管理 |
| | | 3. **创建任务** - 新建任务 |
| | | 4. **消息** - 系统消息和通知 |
| | | 5. **我的** - 个人中心和设置 |
| | | |
| | | * 配套后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) 或 [RuoYi-Cloud](https://github.com/yangzongzhuan/RuoYi-Cloud) 版本。 |
| | | * 应用框架基于[uniapp](https://uniapp.dcloud.net.cn/),支持小程序、H5、Android和IOS。 |
| | | * 前端组件采用[uni-ui](https://github.com/dcloudio/uni-ui),全端兼容的高性能UI框架。 |
| | | * 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip) |
| | | ## 登录功能 |
| | | - 账号密码登录 |
| | | - 微信一键登录(支持微信小程序) |
| | | |
| | | ## 运行方式 |
| | | ```bash |
| | | # 安装依赖 |
| | | npm install |
| | | |
| | | ## 技术文档 |
| | | # 运行到H5 |
| | | npm run dev:h5 |
| | | |
| | | - 官网网站:[http://ruoyi.vip](http://ruoyi.vip) |
| | | - 文档地址:[http://doc.ruoyi.vip](http://doc.ruoyi.vip) |
| | | - H5页体验:[http://h5.ruoyi.vip](http://h5.ruoyi.vip) |
| | | - QQ交流群: ①133713780(满)、②146013835(满)、③189091635 |
| | | - 小程序体验 |
| | | # 运行到微信小程序 |
| | | npm run dev:mp-weixin |
| | | |
| | | <img src="https://oscimg.oschina.net/oscnet/up-26c76dc90b92acdbd9ac8cd5252f07c8ad9.jpg" alt="小程序演示"/> |
| | | # 构建生产版本 |
| | | npm run build |
| | | ``` |
| | | |
| | | ## 目录结构 |
| | | ``` |
| | | app/ |
| | | ├── api/ # 接口请求 |
| | | ├── components/ # 组件 |
| | | ├── pages/ # 页面 |
| | | ├── static/ # 静态资源 |
| | | ├── store/ # 状态管理 |
| | | ├── utils/ # 工具函数 |
| | | └── ... |
| | | ``` |
| | | |
| | | ## 演示图 |
| | | |
| | | <table> |
| | | <tr> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-21f6f842fdc94540469b4eb43fdadbaf7f8.png"/></td> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-a6f23cf9a371a30165e135eff6d9ae89a9d.png"/></td> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-ff5f62016bf6624c1ff27eee57499dccd44.png"/></td> |
| | | </tr> |
| | | <tr> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-b9a582fdb26ec69d407fabd044d2c8494df.png"/></td> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-96427ee08fca29d77934cfc8d1b1a637cef.png"/></td> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-5fdadc582d24cccd7727030d397b63185a3.png"/></td> |
| | | </tr> |
| | | <tr> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-0a36797b6bcc50c36d40c3c782665b89efc.png"/></td> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-d77995cc00687cedd00d5ac7d68a07ea276.png"/></td> |
| | | <td><img src="https://oscimg.oschina.net/oscnet/up-fa8f5ab20becf59b4b38c1b92a9989e7109.png"/></td> |
| | | </tr> |
| | | </table> |
| | | ## 注意事项 |
| | | 1. 微信登录功能需要在微信开发者工具中测试 |
| | | 2. 后端接口需要根据实际情况调整 |
| | | 3. 图标资源已包含在static/icons目录中 |
| New file |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 微信登录 |
| | | export function wechatLogin(data) { |
| | | return request({ |
| | | url: '/wechat/login', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // 获取微信用户信息 |
| | | export function getWechatUserInfo(openid) { |
| | | return request({ |
| | | url: '/wechat/user/' + openid, |
| | | method: 'get' |
| | | }) |
| | | } |
| | | |
| | | // 绑定微信账号 |
| | | export function bindWechat(data) { |
| | | return request({ |
| | | url: '/wechat/bind', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // 解绑微信账号 |
| | | export function unbindWechat(data) { |
| | | return request({ |
| | | url: '/wechat/unbind', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | |
| | | "navigationBarTitleText": "登录" |
| | | } |
| | | }, { |
| | | "path": "pages/login/wechat", |
| | | "style": { |
| | | "navigationBarTitleText": "微信登录" |
| | | } |
| | | }, { |
| | | "path": "pages/register", |
| | | "style": { |
| | | "navigationBarTitleText": "注册" |
| | |
| | | "style": { |
| | | "navigationBarTitleText": "若依移动端框架", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, { |
| | | "path": "pages/bind-vehicle", |
| | | "style": { |
| | | "navigationBarTitleText": "绑定车辆" |
| | | } |
| | | }, { |
| | | "path": "pages/work/index", |
| | |
| | | "style": { |
| | | "navigationBarTitleText": "浏览文本" |
| | | } |
| | | }, { |
| | | "path": "pages/task/index", |
| | | "style": { |
| | | "navigationBarTitleText": "任务列表" |
| | | } |
| | | }, { |
| | | "path": "pages/task/create", |
| | | "style": { |
| | | "navigationBarTitleText": "创建任务" |
| | | } |
| | | }, { |
| | | "path": "pages/task/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "任务详情" |
| | | } |
| | | }, { |
| | | "path": "pages/task/settlement", |
| | | "style": { |
| | | "navigationBarTitleText": "任务结算" |
| | | } |
| | | }, { |
| | | "path": "pages/message/index", |
| | | "style": { |
| | | "navigationBarTitleText": "消息中心" |
| | | } |
| | | }], |
| | | "tabBar": { |
| | | "color": "#000000", |
| | |
| | | "backgroundColor": "#ffffff", |
| | | "list": [{ |
| | | "pagePath": "pages/index", |
| | | "iconPath": "static/images/tabbar/home.png", |
| | | "selectedIconPath": "static/images/tabbar/home_.png", |
| | | "iconPath": "static/icons/home.png", |
| | | "selectedIconPath": "static/icons/home-active.png", |
| | | "text": "首页" |
| | | }, { |
| | | "pagePath": "pages/work/index", |
| | | "iconPath": "static/images/tabbar/work.png", |
| | | "selectedIconPath": "static/images/tabbar/work_.png", |
| | | "text": "工作台" |
| | | "pagePath": "pages/task/index", |
| | | "iconPath": "static/icons/tasks.png", |
| | | "selectedIconPath": "static/icons/tasks-active.png", |
| | | "text": "任务" |
| | | }, { |
| | | "pagePath": "pages/task/create", |
| | | "iconPath": "static/icons/create.png", |
| | | "selectedIconPath": "static/icons/create-active.png", |
| | | "text": "创建任务" |
| | | }, { |
| | | "pagePath": "pages/message/index", |
| | | "iconPath": "static/icons/messages.png", |
| | | "selectedIconPath": "static/icons/messages-active.png", |
| | | "text": "消息" |
| | | }, { |
| | | "pagePath": "pages/mine/index", |
| | | "iconPath": "static/images/tabbar/mine.png", |
| | | "selectedIconPath": "static/images/tabbar/mine_.png", |
| | | "iconPath": "static/icons/profile.png", |
| | | "selectedIconPath": "static/icons/profile-active.png", |
| | | "text": "我的" |
| | | } |
| | | ] |
| New file |
| | |
| | | <template> |
| | | <view class="bind-vehicle-container"> |
| | | <view class="header"> |
| | | <text class="title">绑定车辆</text> |
| | | </view> |
| | | |
| | | <!-- 扫码绑定 --> |
| | | <view class="scan-section"> |
| | | <view class="section-title">扫一扫绑定</view> |
| | | <view class="scan-content"> |
| | | <view class="scan-icon" @click="scanQRCode"> |
| | | <uni-icons type="scan" size="40" color="#007AFF"></uni-icons> |
| | | <text class="scan-text">点击扫码绑定车辆</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 下拉选择绑定 --> |
| | | <view class="form-section"> |
| | | <view class="section-title">选择车牌号绑定</view> |
| | | <view class="form-item"> |
| | | <view class="form-label">车牌号</view> |
| | | <picker mode="selector" :range="vehiclePlates" @change="onVehiclePlateChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedVehiclePlate || '请选择车牌号' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-actions"> |
| | | <button class="submit-btn" @click="bindVehicle" :disabled="!selectedVehiclePlate">确认绑定</button> |
| | | <button class="cancel-btn" @click="goBack">取消</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | selectedVehiclePlate: '', |
| | | // 模拟车辆列表数据 |
| | | vehiclePlates: ['粤A12345', '粤B67890', '粤C11111', '粤D22222', '粤E33333'] |
| | | } |
| | | }, |
| | | methods: { |
| | | // 扫码绑定车辆 |
| | | scanQRCode() { |
| | | // #ifdef H5 |
| | | this.$modal.showToast('H5环境暂不支持扫码功能') |
| | | // #endif |
| | | |
| | | // #ifndef H5 |
| | | uni.scanCode({ |
| | | success: (res) => { |
| | | console.log('扫码结果:', res) |
| | | // 解析扫码结果,这里假设扫码结果是车牌号 |
| | | this.selectedVehiclePlate = res.result |
| | | this.$modal.showToast('扫码成功,正在绑定车辆...') |
| | | // 扫码成功后自动绑定 |
| | | this.bindVehicle() |
| | | }, |
| | | fail: (err) => { |
| | | console.log('扫码失败:', err) |
| | | this.$modal.showToast('扫码失败,请重试') |
| | | } |
| | | }) |
| | | // #endif |
| | | }, |
| | | |
| | | // 车牌号选择 |
| | | onVehiclePlateChange(e) { |
| | | this.selectedVehiclePlate = this.vehiclePlates[e.detail.value] |
| | | }, |
| | | |
| | | // 绑定车辆 |
| | | bindVehicle() { |
| | | if (!this.selectedVehiclePlate) { |
| | | this.$modal.showToast('请选择车牌号') |
| | | return |
| | | } |
| | | |
| | | // 这里可以调用API进行车辆绑定 |
| | | this.$modal.confirm('确认绑定车辆 ' + this.selectedVehiclePlate + ' 吗?').then(() => { |
| | | this.$modal.showToast('车辆绑定成功') |
| | | // 返回上一页 |
| | | this.$tab.navigateBack() |
| | | }).catch(() => { |
| | | // 用户取消操作 |
| | | }) |
| | | }, |
| | | |
| | | goBack() { |
| | | this.$tab.navigateBack() |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .bind-vehicle-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .header { |
| | | text-align: center; |
| | | padding: 40rpx 0; |
| | | |
| | | .title { |
| | | font-size: 40rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin: 30rpx 0 20rpx 0; |
| | | color: #333; |
| | | } |
| | | |
| | | .scan-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .scan-content { |
| | | text-align: center; |
| | | padding: 40rpx 0; |
| | | |
| | | .scan-icon { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | .scan-text { |
| | | margin-top: 20rpx; |
| | | font-size: 28rpx; |
| | | color: #007AFF; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .form-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .form-item { |
| | | margin-bottom: 40rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .form-label { |
| | | font-size: 28rpx; |
| | | margin-bottom: 15rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .form-input { |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | |
| | | &.picker-input { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .form-actions { |
| | | display: flex; |
| | | margin-top: 50rpx; |
| | | |
| | | .submit-btn, .cancel-btn { |
| | | flex: 1; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | margin: 0 10rpx; |
| | | } |
| | | |
| | | .submit-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | |
| | | &[disabled] { |
| | | background-color: #cccccc; |
| | | } |
| | | } |
| | | |
| | | .cancel-btn { |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <view class="content"> |
| | | <image class="logo" src="@/static/logo.png"></image> |
| | | <view class="text-area"> |
| | | <text class="title">Hello RuoYi</text> |
| | | <view class="home-container"> |
| | | <!-- 顶部用户信息区域 --> |
| | | <view class="user-info-section"> |
| | | <view class="user-info-content"> |
| | | <view class="user-details"> |
| | | <view class="user-name">{{ userName || '未登录' }}</view> |
| | | <view class="vehicle-info"> |
| | | <text v-if="boundVehicle">关联车牌号:{{ boundVehicle }}</text> |
| | | <text v-else>未绑定车牌号</text> |
| | | </view> |
| | | </view> |
| | | <button |
| | | class="bind-vehicle-btn" |
| | | @click="goToBindVehicle" |
| | | > |
| | | {{ boundVehicle ? '更换车辆' : '绑定车辆' }} |
| | | </button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 消息入口 --> |
| | | <view class="message-entry" @click="goToMessages"> |
| | | <view class="message-icon"> |
| | | <uni-icons type="chat" size="24" color="#007AFF"></uni-icons> |
| | | </view> |
| | | <view class="message-text">消息中心</view> |
| | | <view class="unread-dot" v-if="unreadMessageCount > 0">{{ unreadMessageCount }}</view> |
| | | <view class="arrow"> |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 正在运行的任务标题 --> |
| | | <view class="running-tasks-header"> |
| | | <text class="header-title">正在运行的任务</text> |
| | | </view> |
| | | |
| | | <!-- 正在运行的任务列表 --> |
| | | <scroll-view class="running-tasks-section" scroll-y="true"> |
| | | <view class="task-list"> |
| | | <view class="task-item" v-for="task in runningTasks" :key="task.id"> |
| | | <view class="task-main" @click="viewTaskDetail(task)"> |
| | | <view class="task-title">{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view> |
| | | <view class="task-info"> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">任务状态:</view> |
| | | <view class="value">{{ getStatusText(task.status) }}</view> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <view class="label">出发地:</view> |
| | | <view class="value">{{ task.startLocation }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">目的地:</view> |
| | | <view class="value">{{ task.endLocation }}</view> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <view class="label">出发时间:</view> |
| | | <view class="value">{{ task.startTime }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="task-actions"> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'depart') }" |
| | | @click="handleTaskAction(task, 'depart')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 出发 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'arrive') }" |
| | | @click="handleTaskAction(task, 'arrive')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 已到达 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'return') }" |
| | | @click="handleTaskAction(task, 'return')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 返程 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'settle') }" |
| | | @click="handleTaskAction(task, 'settle')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 结算 |
| | | </button> |
| | | <button |
| | | class="action-btn primary" |
| | | :class="{ disabled: isActionDisabled(task, 'complete') }" |
| | | @click="handleTaskAction(task, 'complete')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 已完成 |
| | | </button> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="no-data" v-if="runningTasks.length === 0"> |
| | | <uni-icons type="info" size="40" color="#ccc"></uni-icons> |
| | | <text>暂无正在运行的任务</text> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | |
| | | export default { |
| | | onLoad: function() { |
| | | data() { |
| | | return { |
| | | // 模拟用户绑定的车辆信息 |
| | | boundVehicle: '粤A12345', // 模拟已绑定车辆 |
| | | |
| | | // 模拟消息数据 |
| | | messages: [ |
| | | { |
| | | id: 1, |
| | | type: 'create', // 创建成功 |
| | | content: 'TD 1011 广州天河->广州东站,时间:13:20 任务创建成功', |
| | | time: '2023-05-15 13:20', |
| | | read: false, |
| | | taskId: 1 |
| | | }, |
| | | { |
| | | id: 2, |
| | | type: 'push', // 任务推送 |
| | | content: 'TD1021 广州天河->广州东站,时间:13:20 出发,请及时处理', |
| | | time: '2023-05-15 13:25', |
| | | read: false, |
| | | taskId: 2 |
| | | }, |
| | | { |
| | | id: 3, |
| | | type: 'status', // 任务状态变更 |
| | | content: 'TD1021 广州天河->广州东站,时间:13:20,任务正在转运中', |
| | | time: '2023-05-15 14:30', |
| | | read: true, |
| | | taskId: 2 |
| | | }, |
| | | { |
| | | id: 4, |
| | | type: 'create', // 创建成功 |
| | | content: 'TD 1022 深圳南山->深圳福田,时间:15:10 任务创建成功', |
| | | time: '2023-05-15 15:10', |
| | | read: false, |
| | | taskId: 3 |
| | | }, |
| | | { |
| | | id: 5, |
| | | type: 'push', // 任务推送 |
| | | content: 'TD1023 深圳南山->深圳福田,时间:16:00 出发,请及时处理', |
| | | time: '2023-05-15 16:00', |
| | | read: true, |
| | | taskId: 4 |
| | | } |
| | | ], |
| | | |
| | | // 模拟正在运行的任务列表 |
| | | taskList: [ |
| | | { |
| | | id: 1, |
| | | title: '紧急维修任务', |
| | | type: 'maintenance', // 维修保养 |
| | | startLocation: '广州市天河区XX路123号', |
| | | endLocation: '广州市白云区YY路456号', |
| | | startTime: '2023-05-15 15:00', |
| | | assignee: '张三', |
| | | status: 'pending', |
| | | vehicle: '粤A12345', |
| | | taskNo: 'RW20230515001' |
| | | }, |
| | | { |
| | | id: 2, |
| | | title: '定期保养任务', |
| | | type: 'maintenance', // 维修保养 |
| | | startLocation: '深圳市南山区XX路789号', |
| | | endLocation: '深圳市福田区YY路999号', |
| | | startTime: '2023-05-14 10:00', |
| | | assignee: '李四', |
| | | status: 'processing', |
| | | vehicle: '粤B67890', |
| | | taskNo: 'RW20230514002' |
| | | }, |
| | | { |
| | | id: 5, |
| | | title: '急救转运任务', |
| | | type: 'emergency', // 急救转运 |
| | | startLocation: '广州市越秀区医院路1号', |
| | | endLocation: '广州市海珠区医院路2号', |
| | | startTime: '2023-05-16 14:00', |
| | | assignee: '张医生,李护士', |
| | | status: 'pending', |
| | | vehicle: '粤E33333', |
| | | taskNo: 'RW20230516005' |
| | | }, |
| | | { |
| | | id: 6, |
| | | title: '福祉车任务', |
| | | type: 'welfare', // 福祉车 |
| | | startLocation: '广州市荔湾区社区路10号', |
| | | endLocation: '广州市天河区养老院路20号', |
| | | startTime: '2023-05-17 08:00', |
| | | assignee: '王司机', |
| | | status: 'processing', |
| | | vehicle: '粤F44444', |
| | | taskNo: 'RW20230517006' |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState({ |
| | | userName: state => state.user.name |
| | | }), |
| | | |
| | | // 正在运行的任务(待处理和处理中的任务) |
| | | runningTasks() { |
| | | return this.taskList.filter(task => |
| | | task.status === 'pending' || task.status === 'processing' |
| | | ); |
| | | }, |
| | | |
| | | // 未读消息数量 |
| | | unreadMessageCount() { |
| | | return this.messages.filter(message => !message.read).length; |
| | | } |
| | | }, |
| | | methods: { |
| | | // 跳转到绑定车辆页面 |
| | | goToBindVehicle() { |
| | | // 跳转到绑定车辆的页面 |
| | | this.$tab.navigateTo('/pages/bind-vehicle'); |
| | | }, |
| | | |
| | | // 跳转到消息页面 |
| | | goToMessages() { |
| | | this.$tab.switchTab('/pages/message/index'); |
| | | }, |
| | | |
| | | // 查看任务详情 |
| | | viewTaskDetail(task) { |
| | | // 跳转到任务详情页面 |
| | | this.$tab.navigateTo(`/pages/task/detail?id=${task.id}`); |
| | | }, |
| | | |
| | | // 判断操作按钮是否禁用 |
| | | isActionDisabled(task, action) { |
| | | // 根据任务状态和操作类型判断是否禁用 |
| | | switch (action) { |
| | | case 'depart': |
| | | return task.status !== 'pending'; |
| | | case 'arrive': |
| | | return task.status !== 'processing'; |
| | | case 'return': |
| | | return task.status !== 'processing'; |
| | | case 'settle': |
| | | return task.status !== 'processing'; |
| | | case 'complete': |
| | | return task.status !== 'processing'; |
| | | default: |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 处理任务操作 |
| | | handleTaskAction(task, action) { |
| | | if (this.isActionDisabled(task, action)) { |
| | | return; |
| | | } |
| | | |
| | | switch (action) { |
| | | case 'depart': |
| | | // 出发操作,根据任务类型显示不同的确认信息 |
| | | let departMessage = '确定要标记为已出发吗?'; |
| | | if (task.type !== 'maintenance' && task.type !== 'refuel' && task.type !== 'inspection') { |
| | | departMessage = '发出去目的地,确认?'; |
| | | } |
| | | this.$modal.confirm(departMessage).then(() => { |
| | | task.status = 'processing'; |
| | | this.$modal.showToast('已出发'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'arrive': |
| | | // 已到达操作 |
| | | this.$modal.confirm('已经到达目的地,确认?').then(() => { |
| | | this.$modal.showToast('已到达'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'return': |
| | | // 返程操作 |
| | | this.$modal.confirm('现在已经返程中,确认?').then(() => { |
| | | this.$modal.showToast('返程中'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'settle': |
| | | // 结算操作,跳转到结算页面 |
| | | this.$tab.navigateTo(`/pages/task/settlement?id=${task.id}`); |
| | | break; |
| | | case 'complete': |
| | | // 已完成操作 |
| | | this.$modal.confirm('任务是否已经全部完成,确认?').then(() => { |
| | | task.status = 'completed'; |
| | | this.$modal.showToast('任务已完成'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | getStatusText(status) { |
| | | const statusMap = { |
| | | 'pending': '待处理', |
| | | 'processing': '处理中', |
| | | 'completed': '已完成' |
| | | } |
| | | return statusMap[status] || '未知' |
| | | }, |
| | | |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'maintenance': '维修保养', |
| | | 'refuel': '加油', |
| | | 'inspection': '巡检', |
| | | 'emergency': '急救转运', |
| | | 'welfare': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .content { |
| | | <style lang="scss"> |
| | | .home-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | // 用户信息区域 |
| | | .user-info-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .user-info-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .user-details { |
| | | .user-name { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 10rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .vehicle-info { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | |
| | | .bind-vehicle-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | padding: 15rpx 30rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 消息入口 |
| | | .message-entry { |
| | | display: flex; |
| | | align-items: center; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | position: relative; |
| | | |
| | | .message-icon { |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .message-text { |
| | | flex: 1; |
| | | font-size: 32rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .unread-dot { |
| | | position: absolute; |
| | | top: 15rpx; |
| | | right: 60rpx; |
| | | background-color: #ff4d4f; |
| | | color: white; |
| | | border-radius: 50%; |
| | | width: 32rpx; |
| | | height: 32rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 20rpx; |
| | | } |
| | | |
| | | .logo { |
| | | height: 200rpx; |
| | | width: 200rpx; |
| | | margin-top: 200rpx; |
| | | margin-left: auto; |
| | | margin-right: auto; |
| | | margin-bottom: 50rpx; |
| | | .arrow { |
| | | margin-left: 20rpx; |
| | | } |
| | | } |
| | | |
| | | .text-area { |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | // 正在运行的任务标题 |
| | | .running-tasks-header { |
| | | margin-bottom: 20rpx; |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .title { |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | color: #8f8f94; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | |
| | | // 正在运行的任务列表 |
| | | .running-tasks-section { |
| | | flex: 1; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .task-list { |
| | | .task-item { |
| | | background-color: #fafafa; |
| | | border-radius: 15rpx; |
| | | margin-bottom: 30rpx; |
| | | overflow: hidden; |
| | | |
| | | .task-main { |
| | | padding: 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .task-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .task-info { |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 15rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | flex: 1; |
| | | display: flex; |
| | | |
| | | .label { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | margin-right: 10rpx; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 26rpx; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-actions { |
| | | display: flex; |
| | | padding: 20rpx; |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 26rpx; |
| | | margin: 0 5rpx; |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.disabled { |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | &:first-child { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .no-data { |
| | | text-align: center; |
| | | padding: 100rpx 0; |
| | | color: #999; |
| | | |
| | | text { |
| | | display: block; |
| | | margin-top: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <view class="normal-login-container"> |
| | | <scroll-view class="normal-login-container" scroll-y="true"> |
| | | <view class="logo-content align-center justify-center flex"> |
| | | <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix"> |
| | | </image> |
| | |
| | | <view class="iconfont icon-password icon"></view> |
| | | <input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" /> |
| | | </view> |
| | | <view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled"> |
| | | <view class="input-item flex align-center captcha-container" v-if="captchaEnabled"> |
| | | <view class="iconfont icon-code icon"></view> |
| | | <input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" /> |
| | | <view class="login-code"> |
| | | <image :src="codeUrl" @click="getCode" class="login-code-img"></image> |
| | | <image :src="codeUrl" @click="getCode" class="login-code-img" mode="aspectFit"></image> |
| | | </view> |
| | | </view> |
| | | <view class="action-btn"> |
| | | <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button> |
| | | </view> |
| | | <view class="wechat-login" @click="handleWechatLogin"> |
| | | <view class="wechat-btn"> |
| | | <image class="wechat-icon" src="/static/icons/profile.png"></image> |
| | | <text class="wechat-text">微信一键登录</text> |
| | | </view> |
| | | </view> |
| | | <view class="reg text-center" v-if="register"> |
| | | <text class="text-grey1">没有账号?</text> |
| | |
| | | <text @click="handlePrivacy" class="text-blue">《隐私协议》</text> |
| | | </view> |
| | | </view> |
| | | |
| | | </view> |
| | | </scroll-view> |
| | | </template> |
| | | |
| | | <script> |
| | |
| | | this.pwdLogin() |
| | | } |
| | | }, |
| | | // 微信登录方法 |
| | | async handleWechatLogin() { |
| | | // #ifdef MP-WEIXIN |
| | | // 微信小程序登录 |
| | | uni.login({ |
| | | provider: 'weixin', |
| | | success: (loginRes) => { |
| | | console.log('微信登录成功', loginRes); |
| | | // 获取用户信息 |
| | | uni.getUserInfo({ |
| | | provider: 'weixin', |
| | | success: (infoRes) => { |
| | | console.log('用户信息获取成功', infoRes); |
| | | // 跳转到微信登录确认页面 |
| | | this.$tab.navigateTo(`/pages/login/wechat?userInfo=${encodeURIComponent(JSON.stringify(infoRes.userInfo))}`); |
| | | }, |
| | | fail: (error) => { |
| | | console.error('获取用户信息失败', error); |
| | | this.$modal.msgError("获取微信用户信息失败"); |
| | | } |
| | | }); |
| | | }, |
| | | fail: (error) => { |
| | | console.error('微信登录失败', error); |
| | | this.$modal.msgError("微信登录失败"); |
| | | } |
| | | }); |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | // H5或其他平台提示 |
| | | this.$modal.msgError("请在微信客户端中使用微信登录功能"); |
| | | // #endif |
| | | }, |
| | | // 密码登录 |
| | | async pwdLogin() { |
| | | this.$store.dispatch('Login', this.loginForm).then(() => { |
| | |
| | | |
| | | .normal-login-container { |
| | | width: 100%; |
| | | min-height: 100vh; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .logo-content { |
| | | width: 100%; |
| | |
| | | .icon { |
| | | font-size: 38rpx; |
| | | margin-left: 10px; |
| | | color: #999; |
| | | } |
| | | |
| | | .input { |
| | | margin-left: 20rpx; |
| | | width: 100%; |
| | | font-size: 14px; |
| | | line-height: 20px; |
| | | text-align: left; |
| | | padding-left: 15px; |
| | | } |
| | | |
| | | } |
| | | |
| | | .login-btn { |
| | | margin-top: 40px; |
| | | height: 45px; |
| | | background: none; |
| | | } |
| | | } |
| | | |
| | | .reg { |
| | | margin-top: 15px; |
| | | .captcha-container { |
| | | width: 100%; |
| | | margin: 20px auto; |
| | | background-color: #f5f6f7; |
| | | height: 45px; |
| | | border-radius: 20px; |
| | | padding-right: 10rpx; |
| | | box-sizing: border-box; |
| | | |
| | | .icon { |
| | | font-size: 38rpx; |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .xieyi { |
| | | color: #333; |
| | | margin-top: 20px; |
| | | .input { |
| | | margin-left: 20rpx; |
| | | width: 60%; |
| | | height: 45px; |
| | | background: none; |
| | | } |
| | | |
| | | .login-code { |
| | | height: 38px; |
| | | float: right; |
| | | width: 30%; |
| | | height: 45px; |
| | | margin-left: 10rpx; |
| | | border-left: 1px solid #e0e0e0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | .login-code-img { |
| | | height: 38px; |
| | | position: absolute; |
| | | margin-left: 10px; |
| | | width: 200rpx; |
| | | } |
| | | max-width: 100%; |
| | | max-height: 45px; |
| | | object-fit: contain; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .action-btn { |
| | | margin: 40rpx 0; |
| | | |
| | | .login-btn { |
| | | height: 90rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | |
| | | .wechat-login { |
| | | margin: 20rpx 0; |
| | | |
| | | .wechat-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #07c160; |
| | | height: 90rpx; |
| | | border-radius: 20px; |
| | | |
| | | .wechat-icon { |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | margin-right: 10rpx; |
| | | } |
| | | |
| | | .wechat-text { |
| | | color: white; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .reg, .xieyi { |
| | | margin: 20rpx 0; |
| | | |
| | | .text-grey1 { |
| | | color: #888; |
| | | } |
| | | |
| | | .text-blue { |
| | | margin: 0 10rpx; |
| | | color: #007AFF; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view class="wechat-login-container"> |
| | | <view class="header"> |
| | | <view class="title">微信授权登录</view> |
| | | <view class="subtitle">即将登录到若依管理系统</view> |
| | | </view> |
| | | |
| | | <view class="user-info-card"> |
| | | <view class="avatar-section"> |
| | | <image |
| | | class="user-avatar" |
| | | :src="wechatUserInfo.avatarUrl || '/static/images/profile.jpg'" |
| | | mode="aspectFill" |
| | | ></image> |
| | | </view> |
| | | |
| | | <view class="info-section"> |
| | | <view class="info-item"> |
| | | <view class="label">昵称</view> |
| | | <view class="value">{{ wechatUserInfo.nickName || '未知用户' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">性别</view> |
| | | <view class="value">{{ genderText }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">地区</view> |
| | | <view class="value">{{ wechatUserInfo.country }} {{ wechatUserInfo.province }} {{ wechatUserInfo.city }}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="agreement-section"> |
| | | <label class="checkbox"> |
| | | <checkbox :checked="agreed" @click="toggleAgreement" /> |
| | | <text class="agreement-text">我已阅读并同意</text> |
| | | <text class="link" @click="handleUserAgrement">《用户协议》</text> |
| | | <text>和</text> |
| | | <text class="link" @click="handlePrivacy">《隐私协议》</text> |
| | | </label> |
| | | </view> |
| | | |
| | | <view class="action-buttons"> |
| | | <button |
| | | class="confirm-btn" |
| | | :class="{ disabled: !agreed }" |
| | | :disabled="!agreed" |
| | | @click="confirmLogin" |
| | | > |
| | | 确认登录 |
| | | </button> |
| | | <button class="cancel-btn" @click="cancelLogin">取消</button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | agreed: false, |
| | | wechatUserInfo: {}, |
| | | globalConfig: getApp().globalData.config |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // 接收从登录页面传递的微信用户信息 |
| | | if (options.userInfo) { |
| | | this.wechatUserInfo = JSON.parse(decodeURIComponent(options.userInfo)) |
| | | console.log('微信用户信息:', this.wechatUserInfo) |
| | | } |
| | | }, |
| | | computed: { |
| | | genderText() { |
| | | const genderMap = { |
| | | 0: '未知', |
| | | 1: '男', |
| | | 2: '女' |
| | | } |
| | | return genderMap[this.wechatUserInfo.gender] || '未知' |
| | | } |
| | | }, |
| | | methods: { |
| | | toggleAgreement() { |
| | | this.agreed = !this.agreed |
| | | }, |
| | | // 隐私协议 |
| | | handlePrivacy() { |
| | | let site = this.globalConfig.appInfo.agreements[0] |
| | | this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`) |
| | | }, |
| | | // 用户协议 |
| | | handleUserAgrement() { |
| | | let site = this.globalConfig.appInfo.agreements[1] |
| | | this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`) |
| | | }, |
| | | // 确认登录 |
| | | async confirmLogin() { |
| | | if (!this.agreed) { |
| | | this.$modal.msgError("请先同意用户协议和隐私协议") |
| | | return |
| | | } |
| | | |
| | | this.$modal.loading("登录中...") |
| | | |
| | | // 这里应该调用后端微信登录接口 |
| | | // 示例代码,实际需要根据后端接口调整 |
| | | /* |
| | | this.$store.dispatch('WechatLogin', { |
| | | openid: this.wechatUserInfo.openId, |
| | | userInfo: this.wechatUserInfo |
| | | }).then(() => { |
| | | this.$modal.closeLoading() |
| | | this.loginSuccess() |
| | | }).catch(() => { |
| | | this.$modal.closeLoading() |
| | | this.$modal.msgError("微信登录失败") |
| | | }) |
| | | */ |
| | | |
| | | // 临时演示用 |
| | | setTimeout(() => { |
| | | this.$modal.closeLoading() |
| | | this.$modal.showToast("微信登录成功") |
| | | this.$tab.reLaunch('/pages/index') |
| | | }, 1000) |
| | | }, |
| | | // 取消登录 |
| | | cancelLogin() { |
| | | this.$modal.confirm('确定要取消登录吗?').then(() => { |
| | | this.$tab.reLaunch('/pages/login') |
| | | }).catch(() => { |
| | | // 取消操作 |
| | | }) |
| | | }, |
| | | // 登录成功后,处理函数 |
| | | loginSuccess(result) { |
| | | // 设置用户信息 |
| | | this.$store.dispatch('GetInfo').then(res => { |
| | | this.$tab.reLaunch('/pages/index') |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .wechat-login-container { |
| | | padding: 40rpx; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 60rpx; |
| | | |
| | | .title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .subtitle { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | |
| | | .user-info-card { |
| | | background-color: white; |
| | | border-radius: 20rpx; |
| | | padding: 40rpx; |
| | | margin-bottom: 40rpx; |
| | | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .avatar-section { |
| | | text-align: center; |
| | | margin-bottom: 40rpx; |
| | | |
| | | .user-avatar { |
| | | width: 120rpx; |
| | | height: 120rpx; |
| | | border-radius: 50%; |
| | | border: 4rpx solid #f0f0f0; |
| | | } |
| | | } |
| | | |
| | | .info-section { |
| | | .info-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | padding: 20rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .label { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 28rpx; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .agreement-section { |
| | | margin-bottom: 60rpx; |
| | | |
| | | .checkbox { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | .agreement-text { |
| | | margin: 0 10rpx; |
| | | } |
| | | |
| | | .link { |
| | | color: #007AFF; |
| | | margin: 0 5rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | .confirm-btn { |
| | | width: 100%; |
| | | height: 80rpx; |
| | | background-color: #07c160; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | margin-bottom: 20rpx; |
| | | |
| | | &.disabled { |
| | | background-color: #cccccc; |
| | | } |
| | | } |
| | | |
| | | .cancel-btn { |
| | | width: 100%; |
| | | height: 80rpx; |
| | | background-color: white; |
| | | color: #333; |
| | | border: 1rpx solid #ddd; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view class="message-container"> |
| | | <view class="message-header"> |
| | | <view class="header-title">消息中心</view> |
| | | </view> |
| | | |
| | | <scroll-view class="message-list-scroll" scroll-y="true"> |
| | | <view class="message-list"> |
| | | <!-- 未读消息在前 --> |
| | | <view |
| | | class="message-item" |
| | | v-for="message in sortedMessages" |
| | | :key="message.id" |
| | | @click="viewMessageDetail(message)" |
| | | > |
| | | <view class="message-main"> |
| | | <view class="message-title"> |
| | | <text class="title-text">{{ getMessageTypeText(message.type) }}</text> |
| | | <view class="unread-dot" v-if="!message.read"></view> |
| | | </view> |
| | | <view class="message-content">{{ message.content }}</view> |
| | | <view class="message-time">{{ message.time }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="no-data" v-if="sortedMessages.length === 0"> |
| | | <uni-icons type="info" size="40" color="#ccc"></uni-icons> |
| | | <text>暂无消息</text> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | // 消息列表 |
| | | messages: [ |
| | | { |
| | | id: 1, |
| | | type: 'create', // 创建成功 |
| | | content: 'TD 1011 广州天河->广州东站,时间:13:20 任务创建成功', |
| | | time: '2023-05-15 13:20', |
| | | read: false, |
| | | taskId: 1 |
| | | }, |
| | | { |
| | | id: 2, |
| | | type: 'push', // 任务推送 |
| | | content: 'TD1021 广州天河->广州东站,时间:13:20 出发,请及时处理', |
| | | time: '2023-05-15 13:25', |
| | | read: false, |
| | | taskId: 2 |
| | | }, |
| | | { |
| | | id: 3, |
| | | type: 'status', // 任务状态变更 |
| | | content: 'TD1021 广州天河->广州东站,时间:13:20,任务正在转运中', |
| | | time: '2023-05-15 14:30', |
| | | read: true, |
| | | taskId: 2 |
| | | }, |
| | | { |
| | | id: 4, |
| | | type: 'create', // 创建成功 |
| | | content: 'TD 1022 深圳南山->深圳福田,时间:15:10 任务创建成功', |
| | | time: '2023-05-15 15:10', |
| | | read: false, |
| | | taskId: 3 |
| | | }, |
| | | { |
| | | id: 5, |
| | | type: 'push', // 任务推送 |
| | | content: 'TD1023 深圳南山->深圳福田,时间:16:00 出发,请及时处理', |
| | | time: '2023-05-15 16:00', |
| | | read: true, |
| | | taskId: 4 |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | computed: { |
| | | // 按未读/已读排序,未读的在前面 |
| | | sortedMessages() { |
| | | return [...this.messages].sort((a, b) => { |
| | | if (a.read === b.read) { |
| | | // 相同状态按时间倒序 |
| | | return new Date(b.time) - new Date(a.time); |
| | | } |
| | | // 未读的排在前面 |
| | | return a.read ? 1 : -1; |
| | | }); |
| | | } |
| | | }, |
| | | methods: { |
| | | // 获取消息类型文本 |
| | | getMessageTypeText(type) { |
| | | const typeMap = { |
| | | 'create': '创建成功', |
| | | 'push': '任务推送', |
| | | 'status': '任务状态' |
| | | } |
| | | return typeMap[type] || '系统消息'; |
| | | }, |
| | | |
| | | // 查看消息详情(跳转到任务详情) |
| | | viewMessageDetail(message) { |
| | | // 标记为已读 |
| | | message.read = true; |
| | | |
| | | // 跳转到任务详情页面 |
| | | if (message.taskId) { |
| | | this.$tab.navigateTo(`/pages/task/detail?id=${message.taskId}`); |
| | | } else { |
| | | this.$modal.showToast('无法找到关联任务'); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .message-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | .message-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 0; |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | |
| | | .message-list-scroll { |
| | | flex: 1; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | .message-list { |
| | | .message-item { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | margin-bottom: 20rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .message-main { |
| | | .message-title { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20rpx; |
| | | |
| | | .title-text { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .unread-dot { |
| | | width: 16rpx; |
| | | height: 16rpx; |
| | | border-radius: 50%; |
| | | background-color: #ff4d4f; |
| | | } |
| | | } |
| | | |
| | | .message-content { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | margin-bottom: 20rpx; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .message-time { |
| | | font-size: 24rpx; |
| | | color: #999; |
| | | text-align: right; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .no-data { |
| | | text-align: center; |
| | | padding: 100rpx 0; |
| | | color: #999; |
| | | |
| | | text { |
| | | display: block; |
| | | margin-top: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <view class="mine-container" :style="{height: `${windowHeight}px`}"> |
| | | <view class="mine-container"> |
| | | <!--顶部个人信息栏--> |
| | | <view class="header-section"> |
| | | <view class="flex padding justify-between"> |
| | |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="content-section"> |
| | | <scroll-view class="content-section" scroll-y="true"> |
| | | <view class="mine-actions grid col-4 text-center"> |
| | | <view class="action-item" @click="handleJiaoLiuQun"> |
| | | <view class="iconfont icon-friendfill text-pink icon"></view> |
| | |
| | | <view class="action-item" @click="handleBuilding"> |
| | | <view class="iconfont icon-dianzan text-green icon"></view> |
| | | <text class="text">点赞我们</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 用户信息展示 --> |
| | | <view class="user-info-section"> |
| | | <view class="info-item"> |
| | | <view class="info-label">用户名:</view> |
| | | <view class="info-value">{{ name || '未登录' }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="info-label">手机号码:</view> |
| | | <view class="info-value">{{ phonenumber || '未绑定' }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="info-label">绑定车辆:</view> |
| | | <view class="info-value">{{ boundVehicle || '未绑定' }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="info-label">App版本号:</view> |
| | | <view class="info-value">{{ version || '1.0.0' }}</view> |
| | | </view> |
| | | |
| | | <!-- 绑定/解绑车辆操作 --> |
| | | <view class="vehicle-actions" v-if="boundVehicle && boundVehicle !== '未绑定'"> |
| | | <button class="unbind-btn" @click="unbindVehicle">取消绑定车辆</button> |
| | | </view> |
| | | <view class="vehicle-actions" v-else> |
| | | <button class="bind-btn" @click="goToBindVehicle">绑定车辆</button> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import storage from '@/utils/storage' |
| | | import { getUserProfile } from "@/api/system/user" |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | name: this.$store.state.user.name, |
| | | phonenumber: '', |
| | | boundVehicle: '', // 模拟绑定的车辆信息 |
| | | version: getApp().globalData.config.appInfo.version |
| | | } |
| | | }, |
| | |
| | | return uni.getSystemInfoSync().windowHeight - 50 |
| | | } |
| | | }, |
| | | onLoad() { |
| | | this.getUserInfo() |
| | | }, |
| | | methods: { |
| | | // 获取用户信息 |
| | | getUserInfo() { |
| | | getUserProfile().then(response => { |
| | | const user = response.data |
| | | this.name = user.userName |
| | | this.phonenumber = user.phonenumber |
| | | // 模拟绑定车辆信息,实际项目中应从用户信息或车辆接口获取 |
| | | this.boundVehicle = '粤A12345' |
| | | }).catch(() => { |
| | | // 获取用户信息失败时使用默认值 |
| | | this.name = this.$store.state.user.name || '未登录' |
| | | this.phonenumber = '未绑定' |
| | | this.boundVehicle = '未绑定' |
| | | }) |
| | | }, |
| | | |
| | | // 跳转到绑定车辆页面 |
| | | goToBindVehicle() { |
| | | this.$tab.navigateTo('/pages/bind-vehicle') |
| | | }, |
| | | |
| | | // 取消绑定车辆 |
| | | unbindVehicle() { |
| | | this.$modal.confirm('是否取消绑定车辆?').then(() => { |
| | | // 这里可以调用API取消绑定车辆 |
| | | this.boundVehicle = '未绑定' |
| | | this.$modal.showToast('取消绑定成功') |
| | | }).catch(() => { |
| | | // 用户取消操作 |
| | | }) |
| | | }, |
| | | |
| | | handleToInfo() { |
| | | this.$tab.navigateTo('/pages/mine/info/index') |
| | | }, |
| | |
| | | |
| | | .mine-container { |
| | | width: 100%; |
| | | height: 100%; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .header-section { |
| | | padding: 15px 15px 45px 15px; |
| | | background-color: #3c96f3; |
| | | color: white; |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .login-tip { |
| | | font-size: 18px; |
| | |
| | | } |
| | | |
| | | .content-section { |
| | | flex: 1; |
| | | position: relative; |
| | | top: -50px; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .mine-actions { |
| | | margin: 15px 15px; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 用户信息展示区域 |
| | | .user-info-section { |
| | | background-color: white; |
| | | border-radius: 8px; |
| | | padding: 20rpx 30rpx; |
| | | margin: 15rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | padding: 15rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | width: 180rpx; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | } |
| | | |
| | | .vehicle-actions { |
| | | padding: 30rpx 0 10rpx 0; |
| | | text-align: center; |
| | | |
| | | .bind-btn, .unbind-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | |
| | | .bind-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | .unbind-btn { |
| | | background-color: #ff4d4f; |
| | | color: white; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <view class="container"> |
| | | <uni-list> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'person-filled'}" title="昵称" :rightText="user.nickName" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'person-filled'}" title="用户名" :rightText="user.userName" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'phone-filled'}" title="手机号码" :rightText="user.phonenumber" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'location-filled'}" title="绑定车辆" :rightText="boundVehicle || '未绑定'" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'info-filled'}" title="App版本号" :rightText="version" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'email-filled'}" title="邮箱" :rightText="user.email" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'auth-filled'}" title="岗位" :rightText="postGroup" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'staff-filled'}" title="角色" :rightText="roleGroup" /> |
| | | <uni-list-item showExtraIcon="true" :extraIcon="{type: 'calendar-filled'}" title="创建日期" :rightText="user.createTime" /> |
| | | </uni-list> |
| | | |
| | | <!-- 绑定/解绑车辆操作 --> |
| | | <view class="vehicle-actions" v-if="boundVehicle"> |
| | | <button class="unbind-btn" @click="unbindVehicle">取消绑定车辆</button> |
| | | </view> |
| | | <view class="vehicle-actions" v-else> |
| | | <button class="bind-btn" @click="goToBindVehicle">绑定车辆</button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | |
| | | return { |
| | | user: {}, |
| | | roleGroup: "", |
| | | postGroup: "" |
| | | postGroup: "", |
| | | boundVehicle: "", // 模拟绑定的车辆信息 |
| | | version: getApp().globalData.config.appInfo.version || "1.0.0" // App版本号 |
| | | } |
| | | }, |
| | | onLoad() { |
| | |
| | | this.roleGroup = response.roleGroup |
| | | this.postGroup = response.postGroup |
| | | }) |
| | | }, |
| | | |
| | | // 跳转到绑定车辆页面 |
| | | goToBindVehicle() { |
| | | this.$tab.navigateTo('/pages/bind-vehicle') |
| | | }, |
| | | |
| | | // 取消绑定车辆 |
| | | unbindVehicle() { |
| | | this.$modal.confirm('是否取消绑定车辆?').then(() => { |
| | | // 这里可以调用API取消绑定车辆 |
| | | this.boundVehicle = "" |
| | | this.$modal.showToast('取消绑定成功') |
| | | }).catch(() => { |
| | | // 用户取消操作 |
| | | }) |
| | | } |
| | | } |
| | | } |
| | |
| | | page { |
| | | background-color: #ffffff; |
| | | } |
| | | |
| | | .vehicle-actions { |
| | | padding: 30rpx; |
| | | text-align: center; |
| | | |
| | | .bind-btn, .unbind-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | |
| | | .bind-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | .unbind-btn { |
| | | background-color: #ff4d4f; |
| | | color: white; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <scroll-view class="create-task-container" scroll-y="true"> |
| | | <!-- 任务类型选择界面 --> |
| | | <view v-if="!selectedTaskCategory" class="task-category-container"> |
| | | <view class="header"> |
| | | <view class="title">选择任务类型</view> |
| | | <view class="subtitle">请选择您要创建的任务类型</view> |
| | | </view> |
| | | |
| | | <view class="category-list"> |
| | | <view |
| | | class="category-item" |
| | | v-for="(category, index) in taskCategories" |
| | | :key="index" |
| | | @click="selectTaskCategory(category)" |
| | | > |
| | | <view class="icon"> |
| | | <uni-icons :type="category.icon" size="30" :color="category.color"></uni-icons> |
| | | </view> |
| | | <view class="info"> |
| | | <view class="name">{{ category.name }}</view> |
| | | <view class="desc">{{ category.description }}</view> |
| | | </view> |
| | | <view class="arrow"> |
| | | <uni-icons type="arrowright" size="20" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 任务创建表单 --> |
| | | <view v-else class="task-form-container"> |
| | | <view class="form-header"> |
| | | <view class="back-btn" @click="backToCategory"> |
| | | <uni-icons type="arrowleft" size="20"></uni-icons> |
| | | </view> |
| | | <view class="title">创建{{ selectedTaskCategory.name }}任务</view> |
| | | </view> |
| | | |
| | | <view class="form-section"> |
| | | <!-- 普通任务表单 --> |
| | | <view v-if="selectedTaskCategory.type === 'normal'"> |
| | | <view class="form-item"> |
| | | <view class="form-label">任务车辆</view> |
| | | <picker mode="selector" :range="vehicles" @change="onVehicleChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedVehicle || '请选择任务车辆' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务类型</view> |
| | | <input |
| | | class="form-input" |
| | | :value="selectedTaskCategory.name" |
| | | disabled |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务描述</view> |
| | | <textarea |
| | | class="form-textarea" |
| | | placeholder="请输入任务描述" |
| | | v-model="taskForm.description" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务出发地</view> |
| | | <view class="form-input picker-input" @click="selectStartLocation"> |
| | | {{ taskForm.startLocation || '请选择任务出发地' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务目的地</view> |
| | | <view class="form-input picker-input" @click="selectEndLocation"> |
| | | {{ taskForm.endLocation || '请选择任务目的地' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">行驶公里数</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入行驶公里数" |
| | | v-model="taskForm.distance" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">开始时间</view> |
| | | <!-- 使用uni-datetime-picker组件 --> |
| | | <uni-datetime-picker |
| | | v-model="taskForm.startTime" |
| | | type="datetime" |
| | | :placeholder="'请选择开始时间'" |
| | | class="form-input" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">结束时间</view> |
| | | <!-- 使用uni-datetime-picker组件 --> |
| | | <uni-datetime-picker |
| | | v-model="taskForm.endTime" |
| | | type="datetime" |
| | | :placeholder="'请选择结束时间'" |
| | | class="form-input" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">执行人</view> |
| | | <input |
| | | class="form-input" |
| | | :value="currentUser.name" |
| | | disabled |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">备注</view> |
| | | <textarea |
| | | class="form-textarea" |
| | | placeholder="请输入备注信息(最多200字)" |
| | | v-model="taskForm.remark" |
| | | maxlength="200" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 急救转运任务表单 --> |
| | | <view v-else-if="selectedTaskCategory.type === 'emergency'"> |
| | | <view class="form-item"> |
| | | <view class="form-label">任务车辆</view> |
| | | <picker mode="selector" :range="vehicles" @change="onVehicleChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedVehicle || '请选择任务车辆' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">执行任务人员</view> |
| | | <view class="staff-list"> |
| | | <view class="staff-item"> |
| | | <text>{{ currentUser.name }} ({{ currentUser.position }})</text> |
| | | <uni-icons type="checkmarkempty" size="20" color="#007AFF"></uni-icons> |
| | | </view> |
| | | <view |
| | | class="staff-item" |
| | | v-for="(staff, index) in additionalStaff" |
| | | :key="index" |
| | | @click="removeStaff(index)" |
| | | > |
| | | <text>{{ staff.name }} ({{ staff.position }})</text> |
| | | <uni-icons type="closeempty" size="20" color="#ff4d4f"></uni-icons> |
| | | </view> |
| | | <view class="add-staff" @click="addStaff"> |
| | | <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons> |
| | | <text>添加人员</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">归属机构</view> |
| | | <picker mode="selector" :range="organizations" @change="onOrganizationChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedOrganization || '请选择归属机构' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务类型</view> |
| | | <picker mode="selector" :range="emergencyTaskTypes" @change="onEmergencyTaskTypeChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedEmergencyTaskType || '请选择任务类型' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">转运时间</view> |
| | | <!-- 使用uni-datetime-picker组件 --> |
| | | <uni-datetime-picker |
| | | v-model="taskForm.transferTime" |
| | | type="datetime" |
| | | :placeholder="'请选择转运时间'" |
| | | class="form-input" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-section-title">患者信息</view> |
| | | <view class="form-item"> |
| | | <view class="form-label">联系人</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入联系人" |
| | | v-model="taskForm.patient.contact" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">联系电话</view> |
| | | <input |
| | | class="form-input" |
| | | type="number" |
| | | placeholder="请输入联系电话" |
| | | v-model="taskForm.patient.phone" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">患者姓名</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入患者姓名" |
| | | v-model="taskForm.patient.name" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">性别</view> |
| | | <view class="radio-group"> |
| | | <label class="radio-item"> |
| | | <radio value="male" :checked="taskForm.patient.gender === 'male'" @click="taskForm.patient.gender = 'male'" /> |
| | | <text>男</text> |
| | | </label> |
| | | <label class="radio-item"> |
| | | <radio value="female" :checked="taskForm.patient.gender === 'female'" @click="taskForm.patient.gender = 'female'" /> |
| | | <text>女</text> |
| | | </label> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">患者身份证</view> |
| | | <input |
| | | class="form-input" |
| | | type="idcard" |
| | | placeholder="请输入患者身份证号" |
| | | v-model="taskForm.patient.idCard" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">病情</view> |
| | | <textarea |
| | | class="form-textarea" |
| | | placeholder="请输入患者病情描述" |
| | | v-model="taskForm.patient.condition" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-section-title">转出医院信息</view> |
| | | <view class="form-item"> |
| | | <view class="form-label">医院名称</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入转出医院名称" |
| | | v-model="taskForm.hospitalOut.name" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">科室</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入科室" |
| | | v-model="taskForm.hospitalOut.department" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">床号</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入床号" |
| | | v-model="taskForm.hospitalOut.bedNumber" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">转出地址</view> |
| | | <view class="form-input picker-input" @click="selectHospitalOutAddress"> |
| | | {{ taskForm.hospitalOut.address || '请选择转出地址' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-section-title">转入医院信息</view> |
| | | <view class="form-item"> |
| | | <view class="form-label">医院名称</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入转入医院名称" |
| | | v-model="taskForm.hospitalIn.name" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">科室</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入科室" |
| | | v-model="taskForm.hospitalIn.department" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">床号</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入床号" |
| | | v-model="taskForm.hospitalIn.bedNumber" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">转入地址</view> |
| | | <view class="form-input picker-input" @click="selectHospitalInAddress"> |
| | | {{ taskForm.hospitalIn.address || '请选择转入地址' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">转运公里数</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入转运公里数" |
| | | v-model="taskForm.transferDistance" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">成交价</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入成交价" |
| | | v-model="taskForm.price" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 福祉车任务表单 --> |
| | | <view v-else-if="selectedTaskCategory.type === 'welfare'"> |
| | | <view class="form-item"> |
| | | <view class="form-label">任务车辆</view> |
| | | <picker mode="selector" :range="vehicles" @change="onVehicleChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedVehicle || '请选择任务车辆' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">执行任务人员</view> |
| | | <view class="staff-list"> |
| | | <view class="staff-item"> |
| | | <text>{{ currentUser.name }} ({{ currentUser.position }})</text> |
| | | <uni-icons type="checkmarkempty" size="20" color="#007AFF"></uni-icons> |
| | | </view> |
| | | <view |
| | | class="staff-item" |
| | | v-for="(staff, index) in additionalStaff" |
| | | :key="index" |
| | | @click="removeStaff(index)" |
| | | > |
| | | <text>{{ staff.name }} ({{ staff.position }})</text> |
| | | <uni-icons type="closeempty" size="20" color="#ff4d4f"></uni-icons> |
| | | </view> |
| | | <view class="add-staff" @click="addStaff"> |
| | | <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons> |
| | | <text>添加人员</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">归属机构</view> |
| | | <picker mode="selector" :range="organizations" @change="onOrganizationChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedOrganization || '请选择归属机构' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">服务时间</view> |
| | | <!-- 使用uni-datetime-picker组件 --> |
| | | <uni-datetime-picker |
| | | v-model="taskForm.serviceTime" |
| | | type="datetime" |
| | | :placeholder="'请选择服务时间'" |
| | | class="form-input" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-section-title">乘客信息</view> |
| | | <view class="form-item"> |
| | | <view class="form-label">联系人</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入联系人" |
| | | v-model="taskForm.passenger.contact" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">联系电话</view> |
| | | <input |
| | | class="form-input" |
| | | type="number" |
| | | placeholder="请输入联系电话" |
| | | v-model="taskForm.passenger.phone" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">出发地址</view> |
| | | <view class="form-input picker-input" @click="selectStartAddress"> |
| | | {{ taskForm.startAddress || '请选择出发地址' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">目的地址</view> |
| | | <view class="form-input picker-input" @click="selectEndAddress"> |
| | | {{ taskForm.endAddress || '请选择目的地址' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">公里数</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入公里数" |
| | | v-model="taskForm.distance" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">成交价</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入成交价" |
| | | v-model="taskForm.price" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-actions"> |
| | | <button class="submit-btn" @click="submitTask">保存</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue' |
| | | |
| | | export default { |
| | | components: { |
| | | uniDatetimePicker |
| | | }, |
| | | data() { |
| | | return { |
| | | selectedTaskCategory: null, |
| | | selectedVehicle: '', |
| | | selectedOrganization: '', |
| | | selectedEmergencyTaskType: '', |
| | | taskForm: { |
| | | description: '', |
| | | startLocation: '', |
| | | endLocation: '', |
| | | distance: '', |
| | | startTime: '', |
| | | endTime: '', |
| | | remark: '', |
| | | transferTime: '', |
| | | patient: { |
| | | contact: '', |
| | | phone: '', |
| | | name: '', |
| | | gender: 'male', |
| | | idCard: '', |
| | | condition: '' |
| | | }, |
| | | hospitalOut: { |
| | | name: '', |
| | | department: '', |
| | | bedNumber: '', |
| | | address: '' |
| | | }, |
| | | hospitalIn: { |
| | | name: '', |
| | | department: '', |
| | | bedNumber: '', |
| | | address: '' |
| | | }, |
| | | transferDistance: '', |
| | | price: '', |
| | | serviceTime: '', |
| | | passenger: { |
| | | contact: '', |
| | | phone: '' |
| | | }, |
| | | startAddress: '', |
| | | endAddress: '' |
| | | }, |
| | | taskCategories: [ |
| | | { |
| | | type: 'normal', |
| | | name: '维修保养', |
| | | icon: 'repair', |
| | | color: '#007AFF', |
| | | description: '设备维修、保养等日常任务' |
| | | }, |
| | | { |
| | | type: 'normal', |
| | | name: '加油', |
| | | icon: 'fuel', |
| | | color: '#1AAD19', |
| | | description: '车辆加油等任务' |
| | | }, |
| | | { |
| | | type: 'emergency', |
| | | name: '急救转运', |
| | | icon: 'hospital', |
| | | color: '#E54D42', |
| | | description: '紧急医疗转运任务' |
| | | }, |
| | | { |
| | | type: 'welfare', |
| | | name: '福祉车', |
| | | icon: 'car', |
| | | color: '#F37B1D', |
| | | description: '老年人、残疾人等特殊群体用车服务' |
| | | } |
| | | ], |
| | | vehicles: ['粤A12345', '粤B67890', '粤C11111', '粤D22222', '粤E33333'], |
| | | organizations: ['广州分公司', '深圳分公司', '珠海分公司', '佛山分公司'], |
| | | emergencyTaskTypes: ['急救转运', '航空转运'], |
| | | additionalStaff: [] |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState({ |
| | | currentUser: state => ({ |
| | | name: state.user.name || '张三', |
| | | position: '司机' |
| | | }) |
| | | }) |
| | | }, |
| | | methods: { |
| | | selectTaskCategory(category) { |
| | | this.selectedTaskCategory = category |
| | | }, |
| | | |
| | | backToCategory() { |
| | | this.selectedTaskCategory = null |
| | | }, |
| | | |
| | | onVehicleChange(e) { |
| | | this.selectedVehicle = this.vehicles[e.detail.value] |
| | | }, |
| | | |
| | | onOrganizationChange(e) { |
| | | this.selectedOrganization = this.organizations[e.detail.value] |
| | | }, |
| | | |
| | | onEmergencyTaskTypeChange(e) { |
| | | this.selectedEmergencyTaskType = this.emergencyTaskTypes[e.detail.value] |
| | | }, |
| | | |
| | | selectStartLocation() { |
| | | this.$modal.showToast('选择出发地功能开发中') |
| | | }, |
| | | |
| | | selectEndLocation() { |
| | | this.$modal.showToast('选择目的地功能开发中') |
| | | }, |
| | | |
| | | selectHospitalOutAddress() { |
| | | this.$modal.showToast('选择转出医院地址功能开发中') |
| | | }, |
| | | |
| | | selectHospitalInAddress() { |
| | | this.$modal.showToast('选择转入医院地址功能开发中') |
| | | }, |
| | | |
| | | selectStartAddress() { |
| | | this.$modal.showToast('选择出发地址功能开发中') |
| | | }, |
| | | |
| | | selectEndAddress() { |
| | | this.$modal.showToast('选择目的地址功能开发中') |
| | | }, |
| | | |
| | | addStaff() { |
| | | this.$modal.showToast('添加人员功能开发中') |
| | | }, |
| | | |
| | | removeStaff(index) { |
| | | this.additionalStaff.splice(index, 1) |
| | | }, |
| | | |
| | | submitTask() { |
| | | this.$modal.confirm('确定要保存任务吗?').then(() => { |
| | | this.$modal.showToast('任务保存成功') |
| | | // 这里可以调用API保存任务 |
| | | // 保存成功后跳转到任务列表 |
| | | this.$tab.navigateTo('/pages/task/index') |
| | | }).catch(() => { |
| | | // 取消操作 |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .create-task-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .task-category-container { |
| | | .header { |
| | | text-align: center; |
| | | padding: 40rpx 0; |
| | | |
| | | .title { |
| | | font-size: 40rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .subtitle { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | |
| | | .category-list { |
| | | .category-item { |
| | | display: flex; |
| | | align-items: center; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .icon { |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .info { |
| | | flex: 1; |
| | | |
| | | .name { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 10rpx; |
| | | } |
| | | |
| | | .desc { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | |
| | | .arrow { |
| | | margin-left: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-form-container { |
| | | .form-header { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20rpx 0; |
| | | margin-bottom: 30rpx; |
| | | |
| | | .back-btn { |
| | | width: 60rpx; |
| | | height: 60rpx; |
| | | border-radius: 50%; |
| | | background-color: #f0f0f0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | |
| | | .form-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .form-section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin: 40rpx 0 20rpx 0; |
| | | padding-bottom: 10rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | } |
| | | |
| | | .form-item { |
| | | margin-bottom: 40rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .form-label { |
| | | font-size: 28rpx; |
| | | margin-bottom: 15rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .form-input { |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | |
| | | &.picker-input { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | &[disabled] { |
| | | background-color: #f5f5f5; |
| | | color: #999; |
| | | } |
| | | } |
| | | |
| | | .form-textarea { |
| | | width: 100%; |
| | | min-height: 150rpx; |
| | | padding: 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | resize: none; |
| | | } |
| | | |
| | | .radio-group { |
| | | display: flex; |
| | | |
| | | .radio-item { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-right: 30rpx; |
| | | |
| | | radio { |
| | | margin-right: 10rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .staff-list { |
| | | .staff-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx; |
| | | background-color: #f9f9f9; |
| | | border-radius: 10rpx; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .add-staff { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 20rpx; |
| | | border: 1rpx dashed #007AFF; |
| | | border-radius: 10rpx; |
| | | color: #007AFF; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .form-actions { |
| | | margin-top: 50rpx; |
| | | text-align: center; |
| | | |
| | | .submit-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view class="task-detail-container"> |
| | | <view class="task-header"> |
| | | <text class="task-title">{{ task.title }}</text> |
| | | <view class="task-status" :class="'status-' + task.status"> |
| | | {{ getStatusText(task.status) }} |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 普通任务详情 --> |
| | | <view class="task-info-section" v-if="isNormalTask"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发地:</view> |
| | | <view class="value">{{ task.startLocation }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">目的地:</view> |
| | | <view class="value">{{ task.endLocation }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发时间:</view> |
| | | <view class="value">{{ task.startTime }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务描述:</view> |
| | | <view class="value">{{ task.description || '无描述信息' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">行驶公里数:</view> |
| | | <view class="value">{{ task.distance || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">结束时间:</view> |
| | | <view class="value">{{ task.endTime || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">备注:</view> |
| | | <view class="value">{{ task.remark || '无备注' }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 急救转运任务详情 --> |
| | | <view class="task-info-section" v-else-if="task.type === 'emergency'"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">归属机构:</view> |
| | | <view class="value">{{ task.organization || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ task.emergencyTaskType || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">转运时间:</view> |
| | | <view class="value">{{ task.transferTime || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">患者信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">联系人:</view> |
| | | <view class="value">{{ task.patient.contact || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">联系电话:</view> |
| | | <view class="value">{{ task.patient.phone || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">患者姓名:</view> |
| | | <view class="value">{{ task.patient.name || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">性别:</view> |
| | | <view class="value">{{ task.patient.gender === 'male' ? '男' : '女' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">身份证:</view> |
| | | <view class="value">{{ task.patient.idCard || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">病情:</view> |
| | | <view class="value">{{ task.patient.condition || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">转出医院信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">医院名称:</view> |
| | | <view class="value">{{ task.hospitalOut.name || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">科室:</view> |
| | | <view class="value">{{ task.hospitalOut.department || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">床号:</view> |
| | | <view class="value">{{ task.hospitalOut.bedNumber || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">地址:</view> |
| | | <view class="value">{{ task.hospitalOut.address || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">转入医院信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">医院名称:</view> |
| | | <view class="value">{{ task.hospitalIn.name || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">科室:</view> |
| | | <view class="value">{{ task.hospitalIn.department || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">床号:</view> |
| | | <view class="value">{{ task.hospitalIn.bedNumber || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">地址:</view> |
| | | <view class="value">{{ task.hospitalIn.address || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">转运公里数:</view> |
| | | <view class="value">{{ task.transferDistance || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">成交价:</view> |
| | | <view class="value">¥{{ task.price || '未填写' }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 福祉车任务详情 --> |
| | | <view class="task-info-section" v-else-if="task.type === 'welfare'"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">归属机构:</view> |
| | | <view class="value">{{ task.organization || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">服务时间:</view> |
| | | <view class="value">{{ task.serviceTime || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">乘客信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">联系人:</view> |
| | | <view class="value">{{ task.passenger.contact || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">联系电话:</view> |
| | | <view class="value">{{ task.passenger.phone || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发地址:</view> |
| | | <view class="value">{{ task.startAddress || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">目的地址:</view> |
| | | <view class="value">{{ task.endAddress || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">公里数:</view> |
| | | <view class="value">{{ task.distance || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">成交价:</view> |
| | | <view class="value">¥{{ task.price || '未填写' }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 任务操作按钮 (任务未完成时显示) --> |
| | | <view class="task-actions" v-if="task.status !== 'completed'"> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('depart') }" |
| | | @click="handleTaskAction('depart')" |
| | | > |
| | | 出发 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('arrive') }" |
| | | @click="handleTaskAction('arrive')" |
| | | > |
| | | 已到达 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('return') }" |
| | | @click="handleTaskAction('return')" |
| | | > |
| | | 返程 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('settle') }" |
| | | @click="handleTaskAction('settle')" |
| | | > |
| | | 结算 |
| | | </button> |
| | | <button |
| | | class="action-btn primary" |
| | | :class="{ disabled: isActionDisabled('complete') }" |
| | | @click="handleTaskAction('complete')" |
| | | > |
| | | 已完成 |
| | | </button> |
| | | </view> |
| | | |
| | | <view class="action-section"> |
| | | <button class="back-btn" @click="goBack">返回</button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | task: { |
| | | id: 1, |
| | | title: '紧急维修任务', |
| | | type: 'maintenance', |
| | | startLocation: '广州市天河区XX路123号', |
| | | endLocation: '广州市白云区YY路456号', |
| | | startTime: '2023-05-15 15:00', |
| | | assignee: '张三', |
| | | status: 'pending', |
| | | vehicle: '粤A12345', |
| | | taskNo: 'RW20230515001', |
| | | description: '设备故障,需要紧急维修', |
| | | // 普通任务字段 |
| | | distance: '25', |
| | | endTime: '2023-05-15 17:00', |
| | | remark: '维修完成后需要测试', |
| | | // 急救转运任务字段 |
| | | organization: '广州急救中心', |
| | | emergencyTaskType: '急救转运', |
| | | transferTime: '2023-05-15 16:00', |
| | | patient: { |
| | | contact: '李四', |
| | | phone: '13800138000', |
| | | name: '王五', |
| | | gender: 'male', |
| | | idCard: '440100198001011234', |
| | | condition: '突发心脏病' |
| | | }, |
| | | hospitalOut: { |
| | | name: '广州市第一人民医院', |
| | | department: '心内科', |
| | | bedNumber: '101', |
| | | address: '广州市越秀区医院路1号' |
| | | }, |
| | | hospitalIn: { |
| | | name: '广东省人民医院', |
| | | department: '心内科', |
| | | bedNumber: '205', |
| | | address: '广州市天河区医院路2号' |
| | | }, |
| | | transferDistance: '15', |
| | | price: '800', |
| | | // 福祉车任务字段 |
| | | serviceTime: '2023-05-16 09:00', |
| | | passenger: { |
| | | contact: '赵六', |
| | | phone: '13900139000' |
| | | }, |
| | | startAddress: '广州市荔湾区社区路10号', |
| | | endAddress: '广州市天河区养老院路20号' |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | // 判断是否为普通任务 |
| | | isNormalTask() { |
| | | return this.task.type === 'maintenance' || this.task.type === 'refuel' || this.task.type === 'inspection'; |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // 实际项目中这里会通过API获取任务详情 |
| | | // const taskId = options.id; |
| | | // this.getTaskDetail(taskId); |
| | | }, |
| | | methods: { |
| | | goBack() { |
| | | this.$tab.navigateBack(); |
| | | }, |
| | | |
| | | getStatusText(status) { |
| | | const statusMap = { |
| | | 'pending': '待处理', |
| | | 'processing': '处理中', |
| | | 'completed': '已完成' |
| | | } |
| | | return statusMap[status] || '未知' |
| | | }, |
| | | |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'maintenance': '维修保养', |
| | | 'refuel': '加油', |
| | | 'inspection': '巡检', |
| | | 'emergency': '急救转运', |
| | | 'welfare': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | }, |
| | | |
| | | // 判断操作按钮是否禁用 |
| | | isActionDisabled(action) { |
| | | // 根据任务状态和操作类型判断是否禁用 |
| | | switch (action) { |
| | | case 'depart': |
| | | return this.task.status !== 'pending'; |
| | | case 'arrive': |
| | | return this.task.status !== 'processing'; |
| | | case 'return': |
| | | return this.task.status !== 'processing'; |
| | | case 'settle': |
| | | return this.task.status !== 'processing'; |
| | | case 'complete': |
| | | return this.task.status !== 'processing'; |
| | | default: |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 处理任务操作 |
| | | handleTaskAction(action) { |
| | | if (this.isActionDisabled(action)) { |
| | | return; |
| | | } |
| | | |
| | | switch (action) { |
| | | case 'depart': |
| | | // 出发操作,根据任务类型显示不同的确认信息 |
| | | let departMessage = '确定要标记为已出发吗?'; |
| | | if (this.task.type !== 'maintenance' && this.task.type !== 'refuel' && this.task.type !== 'inspection') { |
| | | departMessage = '发出去目的地,确认?'; |
| | | } |
| | | this.$modal.confirm(departMessage).then(() => { |
| | | this.task.status = 'processing'; |
| | | this.$modal.showToast('已出发'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'arrive': |
| | | // 已到达操作 |
| | | this.$modal.confirm('已经到达目的地,确认?').then(() => { |
| | | this.$modal.showToast('已到达'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'return': |
| | | // 返程操作 |
| | | this.$modal.confirm('现在已经返程中,确认?').then(() => { |
| | | this.$modal.showToast('返程中'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'settle': |
| | | // 结算操作,跳转到结算页面 |
| | | this.$tab.navigateTo(`/pages/task/settlement?id=${this.task.id}`); |
| | | break; |
| | | case 'complete': |
| | | // 已完成操作 |
| | | this.$modal.confirm('任务是否已经全部完成,确认?').then(() => { |
| | | this.task.status = 'completed'; |
| | | this.$modal.showToast('任务已完成'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | // 模拟获取任务详情 |
| | | getTaskDetail(taskId) { |
| | | // 这里应该调用API获取任务详情 |
| | | // 暂时使用模拟数据 |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .task-detail-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .task-header { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .task-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .task-status { |
| | | padding: 10rpx 20rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 24rpx; |
| | | font-weight: bold; |
| | | |
| | | &.status-pending { |
| | | background-color: #fff3cd; |
| | | color: #856404; |
| | | } |
| | | |
| | | &.status-processing { |
| | | background-color: #cce5ff; |
| | | color: #004085; |
| | | } |
| | | |
| | | &.status-completed { |
| | | background-color: #d4edda; |
| | | color: #155724; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-info-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin: 30rpx 0 20rpx 0; |
| | | padding-bottom: 10rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | padding-bottom: 0; |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .label { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | margin-right: 20rpx; |
| | | white-space: nowrap; |
| | | width: 150rpx; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 28rpx; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-actions { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | min-width: 30%; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 26rpx; |
| | | margin: 10rpx 5rpx; |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.disabled { |
| | | opacity: 0.5; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .action-section { |
| | | margin-top: 40rpx; |
| | | text-align: center; |
| | | |
| | | .back-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view class="task-container"> |
| | | <!-- 任务列表头部 --> |
| | | <view class="task-list-section"> |
| | | <view class="task-header"> |
| | | <view class="header-title">任务列表</view> |
| | | <view class="header-actions"> |
| | | <button class="search-toggle-btn" @click="toggleSearch"> |
| | | <uni-icons :type="showSearch ? 'close' : 'search'" size="20"></uni-icons> |
| | | </button> |
| | | <button class="refresh-btn" @click="refreshList"> |
| | | <uni-icons type="refresh" size="20"></uni-icons> |
| | | </button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 查询条件区域 --> |
| | | <view class="search-section" v-show="showSearch"> |
| | | <view class="search-form"> |
| | | <view class="form-item"> |
| | | <view class="form-label">任务状态</view> |
| | | <picker mode="selector" :range="statusOptions" @change="onStatusChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedStatusText || '全部状态' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务时间</view> |
| | | <view class="date-range"> |
| | | <!-- 使用uni-datetime-picker组件 --> |
| | | <uni-datetime-picker |
| | | v-model="startDate" |
| | | type="date" |
| | | :placeholder="'开始时间'" |
| | | class="date-input" |
| | | /> |
| | | <text class="divider">至</text> |
| | | <!-- 使用uni-datetime-picker组件 --> |
| | | <uni-datetime-picker |
| | | v-model="endDate" |
| | | type="date" |
| | | :placeholder="'结束时间'" |
| | | class="date-input" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">车牌号</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入车牌号" |
| | | v-model="searchForm.vehicle" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">任务编号</view> |
| | | <input |
| | | class="form-input" |
| | | placeholder="请输入任务编号" |
| | | v-model="searchForm.taskNo" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-actions"> |
| | | <button class="search-btn" @click="handleSearch">查询</button> |
| | | <button class="reset-btn" @click="resetSearch">重置</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="task-filter"> |
| | | <scroll-view class="filter-tabs" scroll-x="true"> |
| | | <view |
| | | class="filter-item" |
| | | :class="{ active: currentFilter === 'all' }" |
| | | @click="changeFilter('all')" |
| | | > |
| | | 全部 |
| | | </view> |
| | | <view |
| | | class="filter-item" |
| | | :class="{ active: currentFilter === 'pending' }" |
| | | @click="changeFilter('pending')" |
| | | > |
| | | 待处理 |
| | | </view> |
| | | <view |
| | | class="filter-item" |
| | | :class="{ active: currentFilter === 'processing' }" |
| | | @click="changeFilter('processing')" |
| | | > |
| | | 处理中 |
| | | </view> |
| | | <view |
| | | class="filter-item" |
| | | :class="{ active: currentFilter === 'completed' }" |
| | | @click="changeFilter('completed')" |
| | | > |
| | | 已完成 |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | |
| | | <scroll-view class="task-list-scroll" scroll-y="true"> |
| | | <view class="task-list"> |
| | | <view class="task-item" v-for="task in filteredTaskList" :key="task.id"> |
| | | <view class="task-main" @click="viewTaskDetail(task)"> |
| | | <view class="task-title">{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view> |
| | | <view class="task-info"> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">任务状态:</view> |
| | | <view class="value">{{ getStatusText(task.status) }}</view> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <view class="label">出发地:</view> |
| | | <view class="value">{{ task.startLocation }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">目的地:</view> |
| | | <view class="value">{{ task.endLocation }}</view> |
| | | </view> |
| | | </view> |
| | | <view class="info-row"> |
| | | <view class="info-item"> |
| | | <view class="label">出发时间:</view> |
| | | <view class="value">{{ task.startTime }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="task-actions"> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'depart') }" |
| | | @click="handleTaskAction(task, 'depart')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 出发 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'arrive') }" |
| | | @click="handleTaskAction(task, 'arrive')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 已到达 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'return') }" |
| | | @click="handleTaskAction(task, 'return')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 返程 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled(task, 'settle') }" |
| | | @click="handleTaskAction(task, 'settle')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 结算 |
| | | </button> |
| | | <button |
| | | class="action-btn primary" |
| | | :class="{ disabled: isActionDisabled(task, 'complete') }" |
| | | @click="handleTaskAction(task, 'complete')" |
| | | v-if="task.status !== 'completed'" |
| | | > |
| | | 已完成 |
| | | </button> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="no-data" v-if="filteredTaskList.length === 0"> |
| | | <uni-icons type="info" size="40" color="#ccc"></uni-icons> |
| | | <text>暂无任务数据</text> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue' |
| | | |
| | | export default { |
| | | components: { |
| | | uniDatetimePicker |
| | | }, |
| | | data() { |
| | | return { |
| | | // 控制查询界面显示/隐藏 |
| | | showSearch: false, |
| | | |
| | | // 查询条件 |
| | | searchForm: { |
| | | vehicle: '', |
| | | taskNo: '' |
| | | }, |
| | | statusOptions: ['全部状态', '待处理', '处理中', '已完成'], |
| | | statusValues: ['', 'pending', 'processing', 'completed'], |
| | | selectedStatus: '', |
| | | selectedStatusText: '', |
| | | startDate: '', |
| | | endDate: '', |
| | | currentFilter: 'all', |
| | | |
| | | // 任务列表 |
| | | taskList: [ |
| | | { |
| | | id: 1, |
| | | title: '紧急维修任务', |
| | | type: 'maintenance', // 维修保养 |
| | | startLocation: '广州市天河区XX路123号', |
| | | endLocation: '广州市白云区YY路456号', |
| | | startTime: '2023-05-15 15:00', |
| | | assignee: '张三', |
| | | status: 'pending', |
| | | vehicle: '粤A12345', |
| | | taskNo: 'RW20230515001' |
| | | }, |
| | | { |
| | | id: 2, |
| | | title: '定期保养任务', |
| | | type: 'maintenance', // 维修保养 |
| | | startLocation: '深圳市南山区XX路789号', |
| | | endLocation: '深圳市福田区YY路999号', |
| | | startTime: '2023-05-14 10:00', |
| | | assignee: '李四', |
| | | status: 'processing', |
| | | vehicle: '粤B67890', |
| | | taskNo: 'RW20230514002' |
| | | }, |
| | | { |
| | | id: 3, |
| | | title: '设备巡检任务', |
| | | type: 'inspection', // 巡检任务 |
| | | startLocation: '珠海市香洲区XX路321号', |
| | | endLocation: '珠海市金湾区YY路654号', |
| | | startTime: '2023-05-13 17:00', |
| | | assignee: '王五', |
| | | status: 'completed', |
| | | vehicle: '粤C11111', |
| | | taskNo: 'RW20230513003' |
| | | }, |
| | | { |
| | | id: 4, |
| | | title: '加油任务', |
| | | type: 'refuel', // 加油 |
| | | startLocation: '佛山市禅城区AA路555号', |
| | | endLocation: '佛山市南海区BB路888号', |
| | | startTime: '2023-05-12 09:00', |
| | | assignee: '赵六', |
| | | status: 'completed', |
| | | vehicle: '粤D22222', |
| | | taskNo: 'RW20230512004' |
| | | }, |
| | | { |
| | | id: 5, |
| | | title: '急救转运任务', |
| | | type: 'emergency', // 急救转运 |
| | | startLocation: '广州市越秀区医院路1号', |
| | | endLocation: '广州市海珠区医院路2号', |
| | | startTime: '2023-05-16 14:00', |
| | | assignee: '张医生,李护士', |
| | | status: 'pending', |
| | | vehicle: '粤E33333', |
| | | taskNo: 'RW20230516005' |
| | | }, |
| | | { |
| | | id: 6, |
| | | title: '福祉车任务', |
| | | type: 'welfare', // 福祉车 |
| | | startLocation: '广州市荔湾区社区路10号', |
| | | endLocation: '广州市天河区养老院路20号', |
| | | startTime: '2023-05-17 08:00', |
| | | assignee: '王司机', |
| | | status: 'processing', |
| | | vehicle: '粤F44444', |
| | | taskNo: 'RW20230517006' |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | computed: { |
| | | filteredTaskList() { |
| | | let filtered = this.taskList; |
| | | |
| | | // 应用筛选器 |
| | | if (this.currentFilter !== 'all') { |
| | | filtered = filtered.filter(task => { |
| | | if (this.currentFilter === 'pending') return task.status === 'pending'; |
| | | if (this.currentFilter === 'processing') return task.status === 'processing'; |
| | | if (this.currentFilter === 'completed') return task.status === 'completed'; |
| | | return true; |
| | | }); |
| | | } |
| | | |
| | | // 应用状态筛选 |
| | | if (this.selectedStatus) { |
| | | filtered = filtered.filter(task => task.status === this.selectedStatus); |
| | | } |
| | | |
| | | // 应用车牌号筛选 |
| | | if (this.searchForm.vehicle) { |
| | | filtered = filtered.filter(task => |
| | | task.vehicle.includes(this.searchForm.vehicle) |
| | | ); |
| | | } |
| | | |
| | | // 应用任务编号筛选 |
| | | if (this.searchForm.taskNo) { |
| | | filtered = filtered.filter(task => |
| | | task.taskNo.includes(this.searchForm.taskNo) |
| | | ); |
| | | } |
| | | |
| | | // 应用时间范围筛选 |
| | | if (this.startDate) { |
| | | filtered = filtered.filter(task => |
| | | task.startTime >= this.startDate |
| | | ); |
| | | } |
| | | |
| | | if (this.endDate) { |
| | | // 结束日期加一天,以便包含当天的数据 |
| | | const end = new Date(this.endDate); |
| | | end.setDate(end.getDate() + 1); |
| | | const endDateStr = end.toISOString().split('T')[0]; |
| | | |
| | | filtered = filtered.filter(task => |
| | | task.startTime < endDateStr |
| | | ); |
| | | } |
| | | |
| | | return filtered; |
| | | } |
| | | }, |
| | | methods: { |
| | | // 切换查询界面显示/隐藏 |
| | | toggleSearch() { |
| | | this.showSearch = !this.showSearch; |
| | | }, |
| | | |
| | | // 状态选择 |
| | | onStatusChange(e) { |
| | | this.selectedStatus = this.statusValues[e.detail.value]; |
| | | this.selectedStatusText = this.statusOptions[e.detail.value]; |
| | | }, |
| | | |
| | | // 查询 |
| | | handleSearch() { |
| | | this.$modal.showToast('查询成功'); |
| | | console.log('查询条件:', { |
| | | status: this.selectedStatus, |
| | | startDate: this.startDate, |
| | | endDate: this.endDate, |
| | | vehicle: this.searchForm.vehicle, |
| | | taskNo: this.searchForm.taskNo |
| | | }); |
| | | // 查询完成后隐藏查询界面 |
| | | this.showSearch = false; |
| | | // 这里可以调用API进行查询 |
| | | }, |
| | | |
| | | // 重置查询条件 |
| | | resetSearch() { |
| | | this.selectedStatus = ''; |
| | | this.selectedStatusText = ''; |
| | | this.startDate = ''; |
| | | this.endDate = ''; |
| | | this.searchForm.vehicle = ''; |
| | | this.searchForm.taskNo = ''; |
| | | }, |
| | | |
| | | // 刷新列表 |
| | | refreshList() { |
| | | this.$modal.showToast('列表已刷新'); |
| | | // 这里可以重新加载数据 |
| | | }, |
| | | |
| | | // 筛选 |
| | | changeFilter(filter) { |
| | | this.currentFilter = filter; |
| | | }, |
| | | |
| | | // 查看任务详情 |
| | | viewTaskDetail(task) { |
| | | // 跳转到任务详情页面 |
| | | this.$tab.navigateTo(`/pages/task/detail?id=${task.id}`); |
| | | }, |
| | | |
| | | // 判断操作按钮是否禁用 |
| | | isActionDisabled(task, action) { |
| | | // 根据任务状态和操作类型判断是否禁用 |
| | | switch (action) { |
| | | case 'depart': |
| | | return task.status !== 'pending'; |
| | | case 'arrive': |
| | | return task.status !== 'processing'; |
| | | case 'return': |
| | | return task.status !== 'processing'; |
| | | case 'settle': |
| | | return task.status !== 'processing'; |
| | | case 'complete': |
| | | return task.status !== 'processing'; |
| | | default: |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 处理任务操作 |
| | | handleTaskAction(task, action) { |
| | | if (this.isActionDisabled(task, action)) { |
| | | return; |
| | | } |
| | | |
| | | switch (action) { |
| | | case 'depart': |
| | | // 出发操作,根据任务类型显示不同的确认信息 |
| | | let departMessage = '确定要标记为已出发吗?'; |
| | | if (task.type !== 'maintenance' && task.type !== 'refuel' && task.type !== 'inspection') { |
| | | departMessage = '发出去目的地,确认?'; |
| | | } |
| | | this.$modal.confirm(departMessage).then(() => { |
| | | task.status = 'processing'; |
| | | this.$modal.showToast('已出发'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'arrive': |
| | | // 已到达操作 |
| | | this.$modal.confirm('已经到达目的地,确认?').then(() => { |
| | | this.$modal.showToast('已到达'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'return': |
| | | // 返程操作 |
| | | this.$modal.confirm('现在已经返程中,确认?').then(() => { |
| | | this.$modal.showToast('返程中'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'settle': |
| | | // 结算操作,跳转到结算页面 |
| | | this.$tab.navigateTo(`/pages/task/settlement?id=${task.id}`); |
| | | break; |
| | | case 'complete': |
| | | // 已完成操作 |
| | | this.$modal.confirm('任务是否已经全部完成,确认?').then(() => { |
| | | task.status = 'completed'; |
| | | this.$modal.showToast('任务已完成'); |
| | | // 这里可以调用API更新任务状态 |
| | | }).catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | getStatusText(status) { |
| | | const statusMap = { |
| | | 'pending': '待处理', |
| | | 'processing': '处理中', |
| | | 'completed': '已完成' |
| | | } |
| | | return statusMap[status] || '未知' |
| | | }, |
| | | |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'maintenance': '维修保养', |
| | | 'refuel': '加油', |
| | | 'inspection': '巡检', |
| | | 'emergency': '急救转运', |
| | | 'welfare': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .task-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | // 任务列表区域 |
| | | .task-list-section { |
| | | flex: 1; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .task-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 0; |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .header-actions { |
| | | display: flex; |
| | | |
| | | .search-toggle-btn, .refresh-btn { |
| | | width: 60rpx; |
| | | height: 60rpx; |
| | | border-radius: 50%; |
| | | background-color: #f0f0f0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-left: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 查询条件区域 |
| | | .search-section { |
| | | background-color: #f9f9f9; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin: 20rpx 0; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .form-item { |
| | | margin-bottom: 30rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .form-label { |
| | | font-size: 28rpx; |
| | | margin-bottom: 15rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .form-input { |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | |
| | | &.picker-input { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | |
| | | .date-range { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | .date-input { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .divider { |
| | | margin: 0 20rpx; |
| | | color: #999; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .form-actions { |
| | | display: flex; |
| | | margin-top: 20rpx; |
| | | |
| | | .search-btn, .reset-btn { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | margin: 0 10rpx; |
| | | } |
| | | |
| | | .search-btn { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-filter { |
| | | margin-bottom: 30rpx; |
| | | flex-shrink: 0; // 防止收缩 |
| | | |
| | | .filter-tabs { |
| | | white-space: nowrap; |
| | | padding: 10rpx 0; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .filter-item { |
| | | display: inline-block; |
| | | padding: 15rpx 30rpx; |
| | | margin-right: 20rpx; |
| | | background-color: #f5f5f5; |
| | | border-radius: 30rpx; |
| | | font-size: 28rpx; |
| | | |
| | | &.active { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-list-scroll { |
| | | flex: 1; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | .task-list { |
| | | .task-item { |
| | | background-color: #fafafa; |
| | | border-radius: 15rpx; |
| | | margin-bottom: 30rpx; |
| | | overflow: hidden; |
| | | |
| | | .task-main { |
| | | padding: 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .task-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .task-info { |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 15rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | flex: 1; |
| | | display: flex; |
| | | |
| | | .label { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | margin-right: 10rpx; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 26rpx; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-actions { |
| | | display: flex; |
| | | padding: 20rpx; |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 26rpx; |
| | | margin: 0 5rpx; |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.disabled { |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | &:first-child { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .no-data { |
| | | text-align: center; |
| | | padding: 100rpx 0; |
| | | color: #999; |
| | | |
| | | text { |
| | | display: block; |
| | | margin-top: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| New file |
| | |
| | | <template> |
| | | <view class="settlement-container"> |
| | | <view class="settlement-header"> |
| | | <text class="header-title">任务结算</text> |
| | | </view> |
| | | |
| | | <scroll-view class="settlement-content" scroll-y="true"> |
| | | <view class="task-info-section"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发地:</view> |
| | | <view class="value">{{ task.startLocation }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">目的地:</view> |
| | | <view class="value">{{ task.endLocation }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="amount-section"> |
| | | <view class="section-title">费用信息</view> |
| | | |
| | | <view class="amount-item"> |
| | | <view class="label">基础费用:</view> |
| | | <view class="value">¥{{ baseAmount }}</view> |
| | | </view> |
| | | |
| | | <view class="amount-item additional-fees" @click="showAdditionalFees"> |
| | | <view class="label">附加费用:</view> |
| | | <view class="value">¥{{ additionalAmount }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="amount-item total-amount"> |
| | | <view class="label">总费用:</view> |
| | | <view class="value total">¥{{ totalAmount }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="settlement-form"> |
| | | <view class="form-item"> |
| | | <view class="form-label">结算金额</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入结算金额" |
| | | v-model="settlementAmount" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">支付方式</view> |
| | | <picker mode="selector" :range="paymentMethods" @change="onPaymentMethodChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedPaymentMethod || '请选择支付方式' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">备注</view> |
| | | <textarea |
| | | class="form-textarea" |
| | | placeholder="请输入备注信息" |
| | | v-model="remark" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 支付二维码区域 --> |
| | | <view v-if="showQRCode" class="qr-code-section"> |
| | | <view class="section-title">请扫码支付</view> |
| | | <view class="qr-code-container"> |
| | | <image class="qr-code" :src="qrCodeImage" mode="widthFix"></image> |
| | | <view class="qr-tip">请使用{{ selectedPaymentMethod }}扫码支付</view> |
| | | </view> |
| | | <view class="payment-status"> |
| | | <view v-if="paymentStatus === 'pending'" class="status-pending">等待支付...</view> |
| | | <view v-if="paymentStatus === 'success'" class="status-success"> |
| | | <uni-icons type="checkmarkempty" size="24" color="#4cd964"></uni-icons> |
| | | 支付成功 |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <view class="action-section"> |
| | | <button |
| | | v-if="!showQRCode || paymentStatus === 'success'" |
| | | class="submit-btn" |
| | | @click="saveSettlement" |
| | | :disabled="!canSave" |
| | | > |
| | | 保存结算 |
| | | </button> |
| | | </view> |
| | | |
| | | <!-- 附加费用弹窗 --> |
| | | <uni-popup ref="additionalFeesPopup" type="bottom"> |
| | | <view class="popup-content"> |
| | | <view class="popup-header"> |
| | | <text class="header-title">附加费用</text> |
| | | <view class="close-btn" @click="closeAdditionalFeesPopup"> |
| | | <uni-icons type="close" size="20" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 简化版费用添加 --> |
| | | <view class="simple-fee-section"> |
| | | <view class="form-item"> |
| | | <view class="form-label">费用类型</view> |
| | | <picker mode="selector" :range="additionalFeeTypeNames" @change="onFeeTypeChange"> |
| | | <view class="form-input picker-input"> |
| | | {{ selectedFeeTypeName || '请选择费用类型' }} |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </picker> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">费用金额</view> |
| | | <input |
| | | class="form-input" |
| | | type="digit" |
| | | placeholder="请输入费用金额" |
| | | v-model="newFeePrice" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="add-fee-btn"> |
| | | <button class="confirm-btn" @click="addCustomFee">添加费用</button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 已添加的费用列表 --> |
| | | <view class="added-fees-list" v-if="selectedAdditionalFees.length > 0"> |
| | | <view class="section-title">已添加费用</view> |
| | | <view |
| | | class="fee-item" |
| | | v-for="(fee, index) in selectedAdditionalFees" |
| | | :key="index" |
| | | > |
| | | <view class="fee-info"> |
| | | <view class="fee-name">{{ fee.name }}</view> |
| | | <view class="fee-price">¥{{ fee.price }} × {{ fee.quantity }}</view> |
| | | </view> |
| | | <view class="fee-total">¥{{ (fee.price * fee.quantity).toFixed(2) }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="popup-footer"> |
| | | <button class="confirm-btn" @click="confirmAdditionalFees">确定</button> |
| | | </view> |
| | | </view> |
| | | </uni-popup> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | task: { |
| | | id: 1, |
| | | taskNo: 'RW20230515001', |
| | | type: 'emergency', |
| | | vehicle: '粤A12345', |
| | | startLocation: '广州市天河区XX路123号', |
| | | endLocation: '广州市白云区YY路456号' |
| | | }, |
| | | baseAmount: 1000, // 基础费用 |
| | | additionalAmount: 0, // 附加费用 |
| | | settlementAmount: '', // 结算金额 |
| | | remark: '', // 备注 |
| | | paymentMethods: ['现金', '支付宝', '微信', '挂帐'], |
| | | selectedPaymentMethod: '', |
| | | showQRCode: false, |
| | | paymentStatus: 'pending', // pending, success |
| | | qrCodeImage: '/static/images/qrcode.png', // 二维码图片路径 |
| | | additionalFeeTypes: [ |
| | | { name: '担架费', price: 200 }, |
| | | { name: '等待费', price: 100 }, |
| | | { name: '善后费', price: 150 }, |
| | | { name: '夜间服务费', price: 300 }, |
| | | { name: '长途费', price: 500 } |
| | | ], |
| | | selectedAdditionalFees: [], // 已选择的附加费用 |
| | | selectedFeeTypeName: '', // 选中的费用类型名称 |
| | | newFeePrice: '' // 新增费用价格 |
| | | } |
| | | }, |
| | | computed: { |
| | | totalAmount() { |
| | | return this.baseAmount + this.additionalAmount; |
| | | }, |
| | | canSave() { |
| | | // 现金和挂帐可以直接保存,其他支付方式需要支付成功后才能保存 |
| | | if (!this.settlementAmount || !this.selectedPaymentMethod) { |
| | | return false; |
| | | } |
| | | |
| | | if (this.selectedPaymentMethod === '现金' || this.selectedPaymentMethod === '挂帐') { |
| | | return true; |
| | | } |
| | | |
| | | // 支付宝、微信等需要支付成功 |
| | | return this.paymentStatus === 'success'; |
| | | }, |
| | | // 获取费用类型名称数组 |
| | | additionalFeeTypeNames() { |
| | | return this.additionalFeeTypes.map(fee => fee.name); |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // 实际项目中这里会通过API获取任务详情 |
| | | // const taskId = options.id; |
| | | // this.getTaskDetail(taskId); |
| | | }, |
| | | methods: { |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'maintenance': '维修保养', |
| | | 'refuel': '加油', |
| | | 'inspection': '巡检', |
| | | 'emergency': '急救转运', |
| | | 'welfare': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | }, |
| | | |
| | | onPaymentMethodChange(e) { |
| | | this.selectedPaymentMethod = this.paymentMethods[e.detail.value]; |
| | | |
| | | // 如果选择支付宝或微信,显示二维码 |
| | | if (this.selectedPaymentMethod === '支付宝' || this.selectedPaymentMethod === '微信') { |
| | | this.showQRCode = true; |
| | | this.paymentStatus = 'pending'; |
| | | // 模拟支付状态检查 |
| | | this.checkPaymentStatus(); |
| | | } else { |
| | | this.showQRCode = false; |
| | | this.paymentStatus = 'pending'; |
| | | } |
| | | }, |
| | | |
| | | // 费用类型选择 |
| | | onFeeTypeChange(e) { |
| | | this.selectedFeeTypeName = this.additionalFeeTypeNames[e.detail.value]; |
| | | }, |
| | | |
| | | checkPaymentStatus() { |
| | | // 模拟支付状态检查,实际项目中应该通过API轮询检查支付状态 |
| | | setTimeout(() => { |
| | | // 模拟支付成功 |
| | | this.paymentStatus = 'success'; |
| | | }, 5000); |
| | | }, |
| | | |
| | | showAdditionalFees() { |
| | | this.$refs.additionalFeesPopup.open(); |
| | | }, |
| | | |
| | | closeAdditionalFeesPopup() { |
| | | this.$refs.additionalFeesPopup.close(); |
| | | }, |
| | | |
| | | // 添加自定义费用 |
| | | addCustomFee() { |
| | | if (!this.selectedFeeTypeName) { |
| | | this.$modal.showToast('请选择费用类型'); |
| | | return; |
| | | } |
| | | |
| | | if (!this.newFeePrice || isNaN(this.newFeePrice) || parseFloat(this.newFeePrice) <= 0) { |
| | | this.$modal.showToast('请输入有效的费用金额'); |
| | | return; |
| | | } |
| | | |
| | | // 查找选中的费用类型信息 |
| | | const selectedFeeType = this.additionalFeeTypes.find(fee => fee.name === this.selectedFeeTypeName); |
| | | |
| | | // 检查是否已存在同名费用 |
| | | const existingFee = this.selectedAdditionalFees.find(fee => fee.name === this.selectedFeeTypeName); |
| | | if (existingFee) { |
| | | existingFee.quantity += 1; |
| | | } else { |
| | | this.selectedAdditionalFees.push({ |
| | | name: this.selectedFeeTypeName, |
| | | price: parseFloat(this.newFeePrice), |
| | | quantity: 1 |
| | | }); |
| | | } |
| | | |
| | | // 清空输入框 |
| | | this.selectedFeeTypeName = ''; |
| | | this.newFeePrice = ''; |
| | | |
| | | this.calculateAdditionalAmount(); |
| | | this.$modal.showToast('费用添加成功'); |
| | | }, |
| | | |
| | | calculateAdditionalAmount() { |
| | | this.additionalAmount = this.selectedAdditionalFees.reduce((total, fee) => { |
| | | return total + (fee.price * fee.quantity); |
| | | }, 0); |
| | | }, |
| | | |
| | | confirmAdditionalFees() { |
| | | this.calculateAdditionalAmount(); |
| | | this.closeAdditionalFeesPopup(); |
| | | }, |
| | | |
| | | saveSettlement() { |
| | | if (!this.settlementAmount) { |
| | | this.$modal.showToast('请输入结算金额'); |
| | | return; |
| | | } |
| | | |
| | | if (!this.selectedPaymentMethod) { |
| | | this.$modal.showToast('请选择支付方式'); |
| | | return; |
| | | } |
| | | |
| | | // 检查结算金额是否合理 |
| | | if (parseFloat(this.settlementAmount) > this.totalAmount) { |
| | | this.$modal.showToast('结算金额不能大于总费用'); |
| | | return; |
| | | } |
| | | |
| | | this.$modal.confirm('确定要保存结算信息吗?').then(() => { |
| | | // 这里应该调用API保存结算信息 |
| | | console.log('结算信息:', { |
| | | taskId: this.task.id, |
| | | baseAmount: this.baseAmount, |
| | | additionalAmount: this.additionalAmount, |
| | | totalAmount: this.totalAmount, |
| | | settlementAmount: this.settlementAmount, |
| | | paymentMethod: this.selectedPaymentMethod, |
| | | remark: this.remark, |
| | | additionalFees: this.selectedAdditionalFees |
| | | }); |
| | | |
| | | this.$modal.showToast('结算信息保存成功'); |
| | | // 返回任务列表 |
| | | this.$tab.navigateBack(); |
| | | }).catch(() => { |
| | | // 取消操作 |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .settlement-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | .settlement-header { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | flex-shrink: 0; |
| | | |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | text-align: center; |
| | | } |
| | | } |
| | | |
| | | .settlement-content { |
| | | flex: 1; |
| | | |
| | | .task-info-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | padding-bottom: 0; |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .label { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | margin-right: 20rpx; |
| | | white-space: nowrap; |
| | | width: 150rpx; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 28rpx; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .amount-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 30rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .amount-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | padding-bottom: 0; |
| | | border-bottom: none; |
| | | } |
| | | |
| | | &.additional-fees { |
| | | .value { |
| | | color: #007AFF; |
| | | } |
| | | } |
| | | |
| | | &.total-amount { |
| | | .label { |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .value.total { |
| | | font-weight: bold; |
| | | font-size: 32rpx; |
| | | color: #e54d42; |
| | | } |
| | | } |
| | | |
| | | .label { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .settlement-form { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .form-item { |
| | | margin-bottom: 40rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .form-label { |
| | | font-size: 28rpx; |
| | | margin-bottom: 15rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .form-input { |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | |
| | | &.picker-input { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | |
| | | .form-textarea { |
| | | width: 100%; |
| | | min-height: 150rpx; |
| | | padding: 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | resize: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .qr-code-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | text-align: center; |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 30rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .qr-code-container { |
| | | margin-bottom: 30rpx; |
| | | |
| | | .qr-code { |
| | | width: 300rpx; |
| | | height: 300rpx; |
| | | margin: 0 auto 20rpx; |
| | | } |
| | | |
| | | .qr-tip { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | |
| | | .payment-status { |
| | | .status-pending { |
| | | font-size: 28rpx; |
| | | color: #ff9900; |
| | | } |
| | | |
| | | .status-success { |
| | | font-size: 28rpx; |
| | | color: #4cd964; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .action-section { |
| | | padding: 20rpx 0; |
| | | flex-shrink: 0; |
| | | |
| | | .submit-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | margin: 0 auto; |
| | | display: block; |
| | | |
| | | &[disabled] { |
| | | background-color: #ccc; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .popup-content { |
| | | background-color: white; |
| | | border-top-left-radius: 20rpx; |
| | | border-top-right-radius: 20rpx; |
| | | padding: 30rpx; |
| | | max-height: 80vh; |
| | | |
| | | .popup-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 30rpx; |
| | | padding-bottom: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .close-btn { |
| | | padding: 10rpx; |
| | | } |
| | | } |
| | | |
| | | .simple-fee-section { |
| | | padding: 20rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | margin-bottom: 20rpx; |
| | | |
| | | .form-item { |
| | | margin-bottom: 30rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .form-label { |
| | | font-size: 28rpx; |
| | | margin-bottom: 15rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .form-input { |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | border: 1rpx solid #eee; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | |
| | | &.picker-input { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .add-fee-btn { |
| | | margin-top: 20rpx; |
| | | |
| | | .confirm-btn { |
| | | width: 100%; |
| | | height: 70rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .added-fees-list { |
| | | margin-bottom: 30rpx; |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 20rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .fee-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 0; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .fee-info { |
| | | .fee-name { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | margin-bottom: 10rpx; |
| | | } |
| | | |
| | | .fee-price { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | } |
| | | } |
| | | |
| | | .fee-total { |
| | | font-size: 28rpx; |
| | | font-weight: bold; |
| | | color: #e54d42; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .popup-footer { |
| | | .confirm-btn { |
| | | width: 100%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | }) |
| | | }) |
| | | }, |
| | | // 输入框 |
| | | prompt(content, defaultValue) { |
| | | return new Promise((resolve, reject) => { |
| | | uni.showModal({ |
| | | title: '系统提示', |
| | | content: content, |
| | | editable: true, |
| | | placeholderText: defaultValue || '', |
| | | cancelText: '取消', |
| | | confirmText: '确定', |
| | | success: function(res) { |
| | | if (res.confirm) { |
| | | resolve(res.content) |
| | | } else { |
| | | reject() |
| | | } |
| | | } |
| | | }) |
| | | }) |
| | | }, |
| | | // 提示信息 |
| | | showToast(option) { |
| | | if (typeof option === "object") { |
| New file |
| | |
| | | # 图标资源 |
| | | |
| | | 此目录用于存放应用所需的图标资源。 |
| | | |
| | | ## 需要的图标 |
| | | |
| | | ### TabBar 图标 |
| | | - `home.png` / `home-active.png` - 首页图标 |
| | | - `tasks.png` / `tasks-active.png` - 任务图标 |
| | | - `create.png` / `create-active.png` - 创建图标 |
| | | - `messages.png` / `messages-active.png` - 消息图标 |
| | | - `profile.png` / `profile-active.png` - 个人中心图标 |
| | | |
| | | ## 图标规格 |
| | | |
| | | - 尺寸: 81px * 81px |
| | | - 格式: PNG |
| | | - 背景: 透明 |
| | | - 颜色: 普通状态 #666666,激活状态 #030213 |
| | | |
| | | ## 使用说明 |
| | | |
| | | 图标文件需要放在此目录下,并在 `src/app.config.ts` 中正确配置路径。 |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <circle cx="40.5" cy="40.5" r="33.75" fill="#030213"/> |
| | | <path d="M40.5 20.25V60.75M20.25 40.5H60.75" stroke="white" stroke-width="4" stroke-linecap="round"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <circle cx="40.5" cy="40.5" r="33.75" fill="#666666"/> |
| | | <path d="M40.5 20.25V60.75M20.25 40.5H60.75" stroke="white" stroke-width="4" stroke-linecap="round"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M40.5 6.75L70.875 27.5625V67.5H54V40.5H27V67.5H10.125V27.5625L40.5 6.75Z" fill="#030213"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M40.5 6.75L70.875 27.5625V67.5H54V40.5H27V67.5H10.125V27.5625L40.5 6.75Z" fill="#666666"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M6.75 20.25H74.25C75.9069 20.25 77.25 21.5931 77.25 23.25V57.75C77.25 59.4069 75.9069 60.75 74.25 60.75H20.25L6.75 74.25V20.25Z" fill="#030213"/> |
| | | <path d="M20.25 33.75H60.75V40.5H20.25V33.75Z" fill="white"/> |
| | | <path d="M20.25 47.25H47.25V54H20.25V47.25Z" fill="white"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M6.75 20.25H74.25C75.9069 20.25 77.25 21.5931 77.25 23.25V57.75C77.25 59.4069 75.9069 60.75 74.25 60.75H20.25L6.75 74.25V20.25Z" fill="#666666"/> |
| | | <path d="M20.25 33.75H60.75V40.5H20.25V33.75Z" fill="white"/> |
| | | <path d="M20.25 47.25H47.25V54H20.25V47.25Z" fill="white"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <circle cx="40.5" cy="27" r="13.5" fill="#030213"/> |
| | | <path d="M13.5 67.5C13.5 54.5 25.5 44.25 40.5 44.25C55.5 44.25 67.5 54.5 67.5 67.5V74.25H13.5V67.5Z" fill="#030213"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <circle cx="40.5" cy="27" r="13.5" fill="#666666"/> |
| | | <path d="M13.5 67.5C13.5 54.5 25.5 44.25 40.5 44.25C55.5 44.25 67.5 54.5 67.5 67.5V74.25H13.5V67.5Z" fill="#666666"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M20.25 6.75H60.75C62.4069 6.75 63.75 8.09315 63.75 9.75V71.25C63.75 72.9069 62.4069 74.25 60.75 74.25H20.25C18.5931 74.25 17.25 72.9069 17.25 71.25V9.75C17.25 8.09315 18.5931 6.75 20.25 6.75Z" fill="#030213"/> |
| | | <path d="M27 20.25H54V27H27V20.25Z" fill="white"/> |
| | | <path d="M27 33.75H54V40.5H27V33.75Z" fill="white"/> |
| | | <path d="M27 47.25H40.5V54H27V47.25Z" fill="white"/> |
| | | </svg> |
| New file |
| | |
| | | <svg width="81" height="81" viewBox="0 0 81 81" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M20.25 6.75H60.75C62.4069 6.75 63.75 8.09315 63.75 9.75V71.25C63.75 72.9069 62.4069 74.25 60.75 74.25H20.25C18.5931 74.25 17.25 72.9069 17.25 71.25V9.75C17.25 8.09315 18.5931 6.75 20.25 6.75Z" fill="#666666"/> |
| | | <path d="M27 20.25H54V27H27V20.25Z" fill="white"/> |
| | | <path d="M27 33.75H54V40.5H27V33.75Z" fill="white"/> |
| | | <path d="M27 47.25H40.5V54H27V47.25Z" fill="white"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" viewBox="0 0 200 200"> |
| | | <rect width="200" height="200" fill="#ffffff"/> |
| | | <g fill="#000000"> |
| | | <rect x="10" y="10" width="10" height="10"/> |
| | | <rect x="20" y="10" width="10" height="10"/> |
| | | <rect x="30" y="10" width="10" height="10"/> |
| | | <rect x="40" y="10" width="10" height="10"/> |
| | | <rect x="50" y="10" width="10" height="10"/> |
| | | <rect x="60" y="10" width="10" height="10"/> |
| | | <rect x="70" y="10" width="10" height="10"/> |
| | | <rect x="80" y="10" width="10" height="10"/> |
| | | <rect x="90" y="10" width="10" height="10"/> |
| | | <rect x="100" y="10" width="10" height="10"/> |
| | | <rect x="110" y="10" width="10" height="10"/> |
| | | <rect x="120" y="10" width="10" height="10"/> |
| | | <rect x="130" y="10" width="10" height="10"/> |
| | | <rect x="140" y="10" width="10" height="10"/> |
| | | <rect x="150" y="10" width="10" height="10"/> |
| | | <rect x="160" y="10" width="10" height="10"/> |
| | | <rect x="170" y="10" width="10" height="10"/> |
| | | <rect x="180" y="10" width="10" height="10"/> |
| | | <rect x="10" y="20" width="10" height="10"/> |
| | | <rect x="40" y="20" width="10" height="10"/> |
| | | <rect x="60" y="20" width="10" height="10"/> |
| | | <rect x="80" y="20" width="10" height="10"/> |
| | | <rect x="100" y="20" width="10" height="10"/> |
| | | <rect x="120" y="20" width="10" height="10"/> |
| | | <rect x="140" y="20" width="10" height="10"/> |
| | | <rect x="160" y="20" width="10" height="10"/> |
| | | <rect x="180" y="20" width="10" height="10"/> |
| | | <rect x="10" y="30" width="10" height="10"/> |
| | | <rect x="20" y="30" width="10" height="10"/> |
| | | <rect x="30" y="30" width="10" height="10"/> |
| | | <rect x="40" y="30" width="10" height="10"/> |
| | | <rect x="60" y="30" width="10" height="10"/> |
| | | <rect x="80" y="30" width="10" height="10"/> |
| | | <rect x="100" y="30" width="10" height="10"/> |
| | | <rect x="120" y="30" width="10" height="10"/> |
| | | <rect x="140" y="30" width="10" height="10"/> |
| | | <rect x="150" y="30" width="10" height="10"/> |
| | | <rect x="160" y="30" width="10" height="10"/> |
| | | <rect x="180" y="30" width="10" height="10"/> |
| | | <rect x="10" y="40" width="10" height="10"/> |
| | | <rect x="20" y="40" width="10" height="10"/> |
| | | <rect x="30" y="40" width="10" height="10"/> |
| | | <rect x="40" y="40" width="10" height="10"/> |
| | | <rect x="60" y="40" width="10" height="10"/> |
| | | <rect x="80" y="40" width="10" height="10"/> |
| | | <rect x="100" y="40" width="10" height="10"/> |
| | | <rect x="120" y="40" width="10" height="10"/> |
| | | <rect x="140" y="40" width="10" height="10"/> |
| | | <rect x="150" y="40" width="10" height="10"/> |
| | | <rect x="160" y="40" width="10" height="10"/> |
| | | <rect x="180" y="40" width="10" height="10"/> |
| | | <rect x="10" y="50" width="10" height="10"/> |
| | | <rect x="40" y="50" width="10" height="10"/> |
| | | <rect x="60" y="50" width="10" height="10"/> |
| | | <rect x="80" y="50" width="10" height="10"/> |
| | | <rect x="100" y="50" width="10" height="10"/> |
| | | <rect x="120" y="50" width="10" height="10"/> |
| | | <rect x="140" y="50" width="10" height="10"/> |
| | | <rect x="160" y="50" width="10" height="10"/> |
| | | <rect x="180" y="50" width="10" height="10"/> |
| | | <rect x="10" y="60" width="10" height="10"/> |
| | | <rect x="20" y="60" width="10" height="10"/> |
| | | <rect x="30" y="60" width="10" height="10"/> |
| | | <rect x="40" y="60" width="10" height="10"/> |
| | | <rect x="50" y="60" width="10" height="10"/> |
| | | <rect x="60" y="60" width="10" height="10"/> |
| | | <rect x="70" y="60" width="10" height="10"/> |
| | | <rect x="80" y="60" width="10" height="10"/> |
| | | <rect x="90" y="60" width="10" height="10"/> |
| | | <rect x="100" y="60" width="10" height="10"/> |
| | | <rect x="110" y="60" width="10" height="10"/> |
| | | <rect x="120" y="60" width="10" height="10"/> |
| | | <rect x="130" y="60" width="10" height="10"/> |
| | | <rect x="140" y="60" width="10" height="10"/> |
| | | <rect x="150" y="60" width="10" height="10"/> |
| | | <rect x="160" y="60" width="10" height="10"/> |
| | | <rect x="170" y="60" width="10" height="10"/> |
| | | <rect x="180" y="60" width="10" height="10"/> |
| | | <rect x="40" y="70" width="10" height="10"/> |
| | | <rect x="80" y="70" width="10" height="10"/> |
| | | <rect x="120" y="70" width="10" height="10"/> |
| | | <rect x="160" y="70" width="10" height="10"/> |
| | | <rect x="10" y="80" width="10" height="10"/> |
| | | <rect x="20" y="80" width="10" height="10"/> |
| | | <rect x="30" y="80" width="10" height="10"/> |
| | | <rect x="40" y="80" width="10" height="10"/> |
| | | <rect x="50" y="80" width="10" height="10"/> |
| | | <rect x="60" y="80" width="10" height="10"/> |
| | | <rect x="70" y="80" width="10" height="10"/> |
| | | <rect x="80" y="80" width="10" height="10"/> |
| | | <rect x="90" y="80" width="10" height="10"/> |
| | | <rect x="100" y="80" width="10" height="10"/> |
| | | <rect x="110" y="80" width="10" height="10"/> |
| | | <rect x="120" y="80" width="10" height="10"/> |
| | | <rect x="130" y="80" width="10" height="10"/> |
| | | <rect x="140" y="80" width="10" height="10"/> |
| | | <rect x="150" y="80" width="10" height="10"/> |
| | | <rect x="160" y="80" width="10" height="10"/> |
| | | <rect x="170" y="80" width="10" height="10"/> |
| | | <rect x="180" y="80" width="10" height="10"/> |
| | | <rect x="20" y="90" width="10" height="10"/> |
| | | <rect x="40" y="90" width="10" height="10"/> |
| | | <rect x="60" y="90" width="10" height="10"/> |
| | | <rect x="80" y="90" width="10" height="10"/> |
| | | <rect x="100" y="90" width="10" height="10"/> |
| | | <rect x="120" y="90" width="10" height="10"/> |
| | | <rect x="140" y="90" width="10" height="10"/> |
| | | <rect x="160" y="90" width="10" height="10"/> |
| | | <rect x="180" y="90" width="10" height="10"/> |
| | | <rect x="10" y="100" width="10" height="10"/> |
| | | <rect x="20" y="100" width="10" height="10"/> |
| | | <rect x="30" y="100" width="10" height="10"/> |
| | | <rect x="40" y="100" width="10" height="10"/> |
| | | <rect x="60" y="100" width="10" height="10"/> |
| | | <rect x="80" y="100" width="10" height="10"/> |
| | | <rect x="100" y="100" width="10" height="10"/> |
| | | <rect x="120" y="100" width="10" height="10"/> |
| | | <rect x="140" y="100" width="10" height="10"/> |
| | | <rect x="150" y="100" width="10" height="10"/> |
| | | <rect x="160" y="100" width="10" height="10"/> |
| | | <rect x="180" y="100" width="10" height="10"/> |
| | | <rect x="10" y="110" width="10" height="10"/> |
| | | <rect x="40" y="110" width="10" height="10"/> |
| | | <rect x="60" y="110" width="10" height="10"/> |
| | | <rect x="80" y="110" width="10" height="10"/> |
| | | <rect x="100" y="110" width="10" height="10"/> |
| | | <rect x="120" y="110" width="10" height="10"/> |
| | | <rect x="140" y="110" width="10" height="10"/> |
| | | <rect x="160" y="110" width="10" height="10"/> |
| | | <rect x="180" y="110" width="10" height="10"/> |
| | | <rect x="10" y="120" width="10" height="10"/> |
| | | <rect x="20" y="120" width="10" height="10"/> |
| | | <rect x="30" y="120" width="10" height="10"/> |
| | | <rect x="40" y="120" width="10" height="10"/> |
| | | <rect x="60" y="120" width="10" height="10"/> |
| | | <rect x="80" y="120" width="10" height="10"/> |
| | | <rect x="100" y="120" width="10" height="10"/> |
| | | <rect x="120" y="120" width="10" height="10"/> |
| | | <rect x="140" y="120" width="10" height="10"/> |
| | | <rect x="150" y="120" width="10" height="10"/> |
| | | <rect x="160" y="120" width="10" height="10"/> |
| | | <rect x="180" y="120" width="10" height="10"/> |
| | | <rect x="10" y="130" width="10" height="10"/> |
| | | <rect x="20" y="130" width="10" height="10"/> |
| | | <rect x="30" y="130" width="10" height="10"/> |
| | | <rect x="40" y="130" width="10" height="10"/> |
| | | <rect x="60" y="130" width="10" height="10"/> |
| | | <rect x="80" y="130" width="10" height="10"/> |
| | | <rect x="100" y="130" width="10" height="10"/> |
| | | <rect x="120" y="130" width="10" height="10"/> |
| | | <rect x="140" y="130" width="10" height="10"/> |
| | | <rect x="150" y="130" width="10" height="10"/> |
| | | <rect x="160" y="130" width="10" height="10"/> |
| | | <rect x="180" y="130" width="10" height="10"/> |
| | | <rect x="10" y="140" width="10" height="10"/> |
| | | <rect x="40" y="140" width="10" height="10"/> |
| | | <rect x="60" y="140" width="10" height="10"/> |
| | | <rect x="80" y="140" width="10" height="10"/> |
| | | <rect x="100" y="140" width="10" height="10"/> |
| | | <rect x="120" y="140" width="10" height="10"/> |
| | | <rect x="140" y="140" width="10" height="10"/> |
| | | <rect x="160" y="140" width="10" height="10"/> |
| | | <rect x="180" y="140" width="10" height="10"/> |
| | | <rect x="10" y="150" width="10" height="10"/> |
| | | <rect x="20" y="150" width="10" height="10"/> |
| | | <rect x="30" y="150" width="10" height="10"/> |
| | | <rect x="40" y="150" width="10" height="10"/> |
| | | <rect x="50" y="150" width="10" height="10"/> |
| | | <rect x="60" y="150" width="10" height="10"/> |
| | | <rect x="70" y="150" width="10" height="10"/> |
| | | <rect x="80" y="150" width="10" height="10"/> |
| | | <rect x="90" y="150" width="10" height="10"/> |
| | | <rect x="100" y="150" width="10" height="10"/> |
| | | <rect x="110" y="150" width="10" height="10"/> |
| | | <rect x="120" y="150" width="10" height="10"/> |
| | | <rect x="130" y="150" width="10" height="10"/> |
| | | <rect x="140" y="150" width="10" height="10"/> |
| | | <rect x="150" y="150" width="10" height="10"/> |
| | | <rect x="160" y="150" width="10" height="10"/> |
| | | <rect x="170" y="150" width="10" height="10"/> |
| | | <rect x="180" y="150" width="10" height="10"/> |
| | | <rect x="40" y="160" width="10" height="10"/> |
| | | <rect x="80" y="160" width="10" height="10"/> |
| | | <rect x="120" y="160" width="10" height="10"/> |
| | | <rect x="160" y="160" width="10" height="10"/> |
| | | <rect x="10" y="170" width="10" height="10"/> |
| | | <rect x="20" y="170" width="10" height="10"/> |
| | | <rect x="30" y="170" width="10" height="10"/> |
| | | <rect x="40" y="170" width="10" height="10"/> |
| | | <rect x="50" y="170" width="10" height="10"/> |
| | | <rect x="60" y="170" width="10" height="10"/> |
| | | <rect x="70" y="170" width="10" height="10"/> |
| | | <rect x="80" y="170" width="10" height="10"/> |
| | | <rect x="90" y="170" width="10" height="10"/> |
| | | <rect x="100" y="170" width="10" height="10"/> |
| | | <rect x="110" y="170" width="10" height="10"/> |
| | | <rect x="120" y="170" width="10" height="10"/> |
| | | <rect x="130" y="170" width="10" height="10"/> |
| | | <rect x="140" y="170" width="10" height="10"/> |
| | | <rect x="150" y="170" width="10" height="10"/> |
| | | <rect x="160" y="170" width="10" height="10"/> |
| | | <rect x="170" y="170" width="10" height="10"/> |
| | | <rect x="180" y="170" width="10" height="10"/> |
| | | <rect x="10" y="180" width="10" height="10"/> |
| | | <rect x="40" y="180" width="10" height="10"/> |
| | | <rect x="60" y="180" width="10" height="10"/> |
| | | <rect x="80" y="180" width="10" height="10"/> |
| | | <rect x="100" y="180" width="10" height="10"/> |
| | | <rect x="120" y="180" width="10" height="10"/> |
| | | <rect x="140" y="180" width="10" height="10"/> |
| | | <rect x="160" y="180" width="10" height="10"/> |
| | | <rect x="180" y="180" width="10" height="10"/> |
| | | <rect x="60" y="190" width="10" height="10"/> |
| | | <rect x="100" y="190" width="10" height="10"/> |
| | | <rect x="140" y="190" width="10" height="10"/> |
| | | </g> |
| | | <text x="100" y="120" font-family="Arial" font-size="20" text-anchor="middle" fill="#000000">支付二维码</text> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <circle cx="12" cy="12" r="10" fill="#000000"/> |
| | | <path d="M12,7L12,17M7,12L17,12" stroke="white" stroke-width="2"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <circle cx="12" cy="12" r="10" fill="#007AFF"/> |
| | | <path d="M12,7L12,17M7,12L17,12" stroke="white" stroke-width="2"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M6,9H18V11H6M14,14H6V12H14M18,8H6V6H18" fill="#000000"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M20,2H4A2,2 0 0,0 2,4V22L6,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M6,9H18V11H6M14,14H6V12H14M18,8H6V6H18" fill="#007AFF"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" fill="#000000"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" fill="#007AFF"/> |
| | | </svg> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
| | | <rect width="24" height="24" fill="#07c160" rx="4"/> |
| | | <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.5 14.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm-9 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm9.5-5.5c-.55 0-1-.45-1-1 0-.55.45-1 1-1s1 .45 1 1-.45 1-1 1zm-10 0c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z" fill="white"/> |
| | | </svg> |
| | |
| | | color: #aaa; |
| | | } |
| | | |
| | | // 隐藏滚动条但保持滚动功能 |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefox滚动条隐藏 |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edge滚动条隐藏 |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | // 全局隐藏滚动条样式 |
| | | scroll-view::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | scroll-view { |
| | | scrollbar-width: none; /* Firefox */ |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .list-cell-arrow::before { |
| | | content: ' '; |
| | | height: 10px; |
| | |
| | | import storage from '@/utils/storage' |
| | | import constant from '@/utils/constant' |
| | | import { login, logout, getInfo } from '@/api/login' |
| | | import { wechatLogin } from '@/api/wechat' |
| | | import { getToken, setToken, removeToken } from '@/utils/auth' |
| | | |
| | | const baseUrl = config.baseUrl |
| | |
| | | }) |
| | | }, |
| | | |
| | | // 微信登录 |
| | | WechatLogin({ commit }, wechatData) { |
| | | return new Promise((resolve, reject) => { |
| | | wechatLogin(wechatData).then(res => { |
| | | setToken(res.token) |
| | | commit('SET_TOKEN', res.token) |
| | | resolve() |
| | | }).catch(error => { |
| | | reject(error) |
| | | }) |
| | | }) |
| | | }, |
| | | |
| | | // 获取用户信息 |
| | | GetInfo({ commit, state }) { |
| | | return new Promise((resolve, reject) => { |