50 Commits
Author SHA1 Message Date
Dawn_Ocean 24f71ed997 fix status display bug in detailframework 2024-03-22 15:58:53 +08:00
Dawn_Ocean 97a8d0570a add button disable in ticketdetail with relavant services 2024-03-22 15:36:18 +08:00
Dawn1Ocean f3f5be793b refactor: merge index & member page 2024-03-22 10:23:39 +08:00
Dawn_Ocean a7c96b2e8c change token_test to wechatUser 2024-03-21 14:38:40 +08:00
Dawn_Ocean 7d1ae68643 change icons to svg in userpage 2024-03-21 11:24:02 +08:00
Dawn_Ocean 3de05c7cfc add avatar in notecard 2024-03-21 11:08:10 +08:00
Dawn_Ocean 7ae5d8758a add requestSubscribeMessage & templateId on ticket submit 2024-03-21 10:48:27 +08:00
Dawn1Ocean 16cb2362e6 banned /user/inform for members 2024-03-20 23:30:53 +08:00
Dawn1Ocean 42ee477ec4 add pre-filling info in repair page 2024-03-20 23:26:54 +08:00
Dawn1Ocean 5b08555359 fix relaunch logic in app.ts 2024-03-20 23:20:39 +08:00
Dawn1Ocean 574d3692cd fix checklogin & getinfo in app.ts 2024-03-20 22:58:03 +08:00
Dawn1Ocean 1f0d4881f3 remove newcomment api 2024-03-20 21:21:23 +08:00
Dawn1Ocean aff74acc1f add /member/checklogin api 2024-03-20 20:04:19 +08:00
Dawn1Ocean 456c891ca6 fix login logic @ app.ts 2024-03-20 14:37:42 +08:00
Dawn1Ocean 952c230148 add about page structure 2024-03-20 01:45:22 +08:00
Dawn1Ocean 9f77cb0f2a add local storage of token and services 2024-03-20 01:00:50 +08:00
Dawn1Ocean f2f4929fc9 add api for login & checklogin 2024-03-19 23:45:16 +08:00
Dawn1Ocean 5c78139d5a add /member/login service; beautify member page with name&avatar 2024-03-19 23:39:01 +08:00
Dawn1Ocean 4f914a7563 beautify ui: /user/member; divider in ticketdetail 2024-03-19 23:07:28 +08:00
Dawn1Ocean 239d4f0c7c change tab-bar logic 2024-03-19 22:54:35 +08:00
Dawn_Ocean db11f03bda add place in mainpage 2024-03-19 22:46:42 +08:00
Dawn_Ocean 56ec1827ca add place in api /duty/info 2024-03-19 21:45:39 +08:00
Dawn1Ocean d705970d1f beautify /user/inform /user/report ui 2024-03-19 19:42:29 +08:00
Dawn1Ocean 2ef04b96a1 add relaunch after change inDutyCnt 2024-03-19 19:19:59 +08:00
Dawn1Ocean 599166e603 add change inDutyCnt button and service 2024-03-19 19:12:33 +08:00
Dawn1Ocean 787b37fc42 beautify member page layout 2024-03-19 17:35:59 +08:00
Dawn1Ocean 3c2b613d87 add support for rendering ui on various devices 2024-03-19 11:31:23 +08:00
Dawn1Ocean f20a38af9b beautify ui; fix current ticket card title display bug 2024-03-19 02:19:39 +08:00
Dawn1Ocean 31d7aea480 beautify ui! 2024-03-19 00:14:13 +08:00
Dawn_Ocean 3db6425dc3 add relaunch ticketdetail after changing it 2024-03-18 14:56:02 +08:00
Dawn_Ocean cd3064c90f add relaunch ticketdetail after changing it 2024-03-18 14:55:27 +08:00
Dawn_Ocean 4640f89ea8 add changeStatus service 2024-03-18 14:40:03 +08:00
Dawn_Ocean 3d5cd6c8da add retrieve in service 2024-03-18 14:22:49 +08:00
Dawn_Ocean 7ced70ab21 fix Fixstatus; add support to all statuses 2024-03-18 14:08:52 +08:00
Dawn_Ocean 2398644cc3 add pickTicket in service 2024-03-18 13:44:39 +08:00
Dawn_Ocean 501f27bfbb add addToOreo in service 2024-03-18 13:39:15 +08:00
Dawn1Ocean e39e8d4e13 update mock 2024-03-17 18:34:58 +08:00
Dawn_Ocean 7cf2cbb798 add en_US localization 2024-03-17 11:34:14 +08:00
Dawn_Ocean d525f0288b add owner's info in ticketdetail 2024-03-17 02:05:08 +08:00
Dawn_Ocean 7f345af777 change README.md 2024-03-17 01:29:56 +08:00
Dawn_Ocean 563a0c42ea add memberpage layout 2024-03-17 01:00:06 +08:00
Dawn_Ocean cce351750d add confirm modal for buttons in ticketdetail 2024-03-16 16:45:41 +08:00
Dawn1Ocean ac9645b987 add comment floatlayout in ticketdetail 2024-03-15 22:19:30 +08:00
Dawn_Ocean e7b0b3239e add modal in ticketdetail-addtooreo 2024-03-15 15:48:19 +08:00
Dawn_Ocean b41498976e add blank judgement; fixed setstate in render bug 2024-03-15 14:28:26 +08:00
Dawn1Ocean 6b554196b3 add blank judgement for forms; fixing setstate bug in detailframework 2024-03-15 13:42:16 +08:00
Dawn1Ocean 2d5ce655ef add member status judgement 2024-03-15 01:58:59 +08:00
Dawn1Ocean 5614ce5818 add uncompleted ticket list in member page 2024-03-15 00:54:05 +08:00
Dawn1Ocean fc3ef61e5d add entry for ticket detail in current ticket card 2024-03-14 23:55:51 +08:00
Dawn1Ocean 60f10eaa8f add random tips on currentTicket card 2024-03-14 23:30:48 +08:00
68 changed files with 2588 additions and 447 deletions
+15 -15
View File
@@ -10,25 +10,25 @@
1. 能看到现在维修状况:有几台正在维修,有几个人值班(空闲状态) 1. 能看到现在维修状况:有几台正在维修,有几个人值班(空闲状态)
2. 能看到自己机器的维修情况:维修进度、评论等 2. 能看到自己机器的维修情况:维修进度、评论等
1. 使用手机号确定id 1. 使用手机号查询工单
## 互动 ## 互动
1. 提醒:当修好之后会向你发送信息,提醒来取 1. 提醒:当修好(工单状态改变为待取回)之后会向你发送信息,提醒来取
2. 线上答疑:协会成员登录账号,看到机主提出的问题可以回答(暂定由值班组长管理) 2. 线上答疑:协会成员登录账号(通过 EVA Auth 授权),看到机主提出的问题可以回答(暂定由值班组长管理)
1. 公开答疑仅回复能不能修,更复杂的问题推荐其来204 1. 公开答疑仅回复能不能修,更复杂的问题推荐其来204
2. 当自己的机器正在维修时,可以与维修人员交流进度和问题等 2. 当自己的机器正在维修时,可以与维修人员交流进度和问题等
3. (暂定)答疑功能使用预填写工单、工单的评论实现 3. 答疑功能使用预填写工单的评论实现
## 信息展示 ## 信息展示
1. 展示协会值班时间(现在是否在值班),若不在值班显示预计值班时间、不值班的原因等 1. 展示协会值班时间(现在是否在值班),若不在值班显示预计值班时间、不值班的原因
2. 展示维修流程,包括注意事项等 2. 展示维修流程,包括注意事项等
1. 戴尔、Surface等不拆 1. 戴尔、Surface等不拆
2. 数据备份提醒 2. 数据备份提醒
3. 不收礼物 3. 不收礼物
4. 不要在204饮食 4. 不要在204饮食
3. (备选)其他语言本地化 3. 其他语言本地化
## 面向协会成员 ## 面向协会成员
@@ -42,13 +42,13 @@
## 对接 ## 对接
1. 与EVA统一身份认证对接 1. 与 EVA 统一身份认证对接
1. 协会成员登录入口 1. 协会成员登录入口
2. 个人信息同步 2. 个人信息同步
2. 与Oreo对接 2. 与 Oreo 对接
1. 维修工单列表查看 1. 维修工单列表查看:七天内未取回的工单
2. 将预填写工单加入Oreo 2. 将预填写工单加入 Oreo
3. 防恶意行为 3. 防恶意行为(尚未设置)
1. 工单填写间隔限制为【1】分钟 1. 工单填写间隔限制为【1】分钟
2. 一个人一天最多能创建【10】个预填写工单 2. 一个人一天最多能创建【10】个预填写工单
3. 黑名单机制 3. 黑名单机制
@@ -65,20 +65,20 @@
## 维修 ## 维修
1. (面向机主)预填写工单 1. 预填写工单
2. 维修进度提示 2. 正在进行工单的展示
3. (面向协会成员)维修列表
## 成员 ## 成员
1. 最近七天内未取回的工单列表 1. 最近七天内未取回的工单列表
2. 值班组长上传本班相关信息 2. 值班组长上传本班相关信息
3. 现在自己是否要值班(值班时间显示) 3. 现在自己是否要值班(值班时间显示)
4. 提醒事项
## 我的 ## 我的
1. 更改手机号等个人信息(手机号可以填写多个) 1. 更改手机号、姓名(手机号暂时只能填写一个)
2. (备选)修改用户名、头像 2. (备选)修改用户名、头像
3. 设置真名(可帮助预填写工单) 3. 设置真名(可帮助预填写工单)
+171 -14
View File
@@ -34,7 +34,7 @@
## 主页面 ## 主页面
### 值班信息 `GET /dutyinfo` ### 值班信息 `GET /duty/info`
#### 当前在值班 #### 当前在值班
@@ -44,7 +44,8 @@ data:
{ {
"isInDuty": true, "isInDuty": true,
"inDutyCnt": 3, "inDutyCnt": 3,
"currentDuty": "2" "currentDuty": "2",
"place": "东三-204"
} }
``` ```
@@ -60,6 +61,44 @@ data:
} }
``` ```
## 账号登陆
### 微信小程序登陆 `POST /login` OK
- Request
```json
{
"code": "wechat_login_code"
}
```
- Response
```json
{
"success": true,
"token": "your_token"
}
```
### 检查 token 是否登陆 `GET /checklogin?token={token}` OK
```json
{
"islogin": true
}
```
- Response
```json
{
"success": true,
"token": "your_token"
}
```
## 用户页面 ## 用户页面
### 个人信息 `GET /user/info` ### 个人信息 `GET /user/info`
@@ -141,17 +180,6 @@ data (same as oreo):
## 工单详情 ## 工单详情
### 创建评论 `POST /tickets/newcomment/{id}`
Request
```json
{
"content": "这是一条评论",
"token": "token_test"
}
```
### 创建工单 `POST /tickets/create` ### 创建工单 `POST /tickets/create`
Request Request
@@ -169,7 +197,74 @@ Request
} }
``` ```
### 工单信息 `GET /tickets/info/{id}` ### 添加评论 `POST /tickets/addnote`
Request
```json
{
"token": "token_test",
"id": "id",
"content" : "为什么 PD 不能充电呢?"
}
```
### 加入 Oreo `POST /tickets/addtooreo`
Request
```json
{
"token": "token_test",
"id": 4234
}
```
### 认领工单 `POST /tickets/pick`
Request
```json
{
"token": "token_test",
"id": 4234
}
```
### 更新工单状态 `POST /tickets/update`
Request
```json
{
"token": "token_test",
"id": "id",
"status": 3
}
```
### 确认已取回 `POST /tickets/retrieve`
Request
```json
{
"token": "token_test",
"id": "id",
}
```
### 获取七天内未完成工单 `POST /tickets/uncompleted`
Request
```json
{
"token": "token_test",
}
```
### 工单信息 `GET /tickets/info?id={id}`
data (same as oreo): data (same as oreo):
@@ -224,3 +319,65 @@ data (same as oreo):
"picked": false "picked": false
} }
``` ```
## 成员相关
### 成员登录 `POST /member/login`
Request
```json
{
"token": "token_test",
"stuid": "3220101984",
"passwd": "sonvidiafuckyou"
}
```
### 检查 token 是否登陆 `GET /member/checklogin?token={token}` OK
data
```json
{
"avatar": "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png",
"name": "宇航员",
"phone": "13311451419",
}
```
### 成员登出 `POST /member/logout`
Request
```json
{
"token": "token_test"
}
```
### 成员值班信息 `GET /member/duty/info`
#### 当前在值班
data:
```json
{
"isInDuty": true,
"inDutyCnt": 3,
"currentDuty": "2"
}
```
#### 当前未值班
data:
```json
{
"isInDuty": false,
"offDutyReason": "学园维修",
"dutyRecoverTime": "下周一"
}
```
+67 -5
View File
@@ -3,13 +3,14 @@ import ticketInfo from './ticketInfo.json';
import uncompleted from './uncompleted.json'; import uncompleted from './uncompleted.json';
export default { export default {
'GET /dutyinfo': { 'GET /duty/info': {
success: true, success: true,
data: { data: {
token: 'token_test', token: 'token_test',
isInDuty: true, isInDuty: true,
inDutyCnt: 3, inDutyCnt: 3,
currentDuty: '2', currentDuty: '2',
place: '204',
}, },
}, },
'GET /user/info': { 'GET /user/info': {
@@ -21,18 +22,21 @@ export default {
}, },
}, },
'POST /user/update': { 'POST /user/update': {
success: true,
data: {}, data: {},
}, },
'GET /user/locale/get': { 'GET /user/locale/get': {
success: true, success: true,
data: { data: {
lang: 'en_US', lang: 'zh_CN',
}, },
}, },
'POST /user/locale/update': { 'POST /user/locale/update': {
success: true,
data: {}, data: {},
}, },
'POST /report': { 'POST /report': {
success: true,
data: {}, data: {},
}, },
'GET /user/mytickets': { 'GET /user/mytickets': {
@@ -43,17 +47,75 @@ export default {
success: true, success: true,
data: ticketInfo, data: ticketInfo,
}, },
'POST /tickets/newcomment': { 'POST /tickets/addnote': {
success: true,
data: {}, data: {},
}, },
'POST /tickets/create': { 'POST /tickets/create': {
success: true,
data: {},
},
'POST /tickets/addtooreo': {
success: true,
data: {},
},
'POST /tickets/pick': {
success: true,
data: {},
},
'POST /tickets/update': {
success: true,
data: {},
},
'POST /tickets/retrieve': {
success: true,
data: {}, data: {},
}, },
'POST /member/login': { 'POST /member/login': {
data: {}, success: true,
data: {
avatar:
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
name: '宇航员',
phone: '13311451419',
},
}, },
'GET /member/tickets/uncompleted': { 'GET /tickets/uncompleted': {
success: true, success: true,
data: uncompleted, data: uncompleted,
}, },
'POST /member/logout': {
success: true,
},
'POST /member/checklogin': {
success: true,
data: {
avatar:
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
name: '宇航员',
phone: '13311451419',
},
},
'GET /member/duty/info': {
success: true,
data: {
token: 'token_test',
isInDuty: true,
inDutyCnt: 6,
currentDuty: '3',
place: '204',
},
},
'POST /login': {
success: true,
data: {
token: '__token_test_zjueva1984__',
},
},
'GET /checklogin': {
success: true,
data: {
islogin: false,
},
},
}; };
+6 -6
View File
@@ -6,13 +6,13 @@
"owner": "唐姐姐", "owner": "唐姐姐",
"phone": "15555555555", "phone": "15555555555",
"description": "清灰", "description": "清灰",
"workers": [], "workers": ["宇航员"],
"createdTime": "2024-03-07T19:52:48.523303", "createdTime": "2024-03-07T19:52:48.523303",
"status": 2, "status": 5,
"isConfirmed": false, "isConfirmed": false,
"notes": [ "notes": [
{ {
"avatar": "https://....jpg", "avatar": "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png",
"id": 21368, "id": 21368,
"op": "宇航员", "op": "宇航员",
"type": 0, "type": 0,
@@ -20,7 +20,7 @@
"createdTime": "2024-03-07T19:52:48.523305" "createdTime": "2024-03-07T19:52:48.523305"
}, },
{ {
"avatar": "https://....jpg", "avatar": "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png",
"id": 21370, "id": 21370,
"op": "宇航员", "op": "宇航员",
"type": 2, "type": 2,
@@ -28,7 +28,7 @@
"createdTime": "2024-03-07T19:58:27.838816" "createdTime": "2024-03-07T19:58:27.838816"
}, },
{ {
"avatar": "https://....jpg", "avatar": "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png",
"id": 21373, "id": 21373,
"op": "宇航员", "op": "宇航员",
"type": 2, "type": 2,
@@ -36,7 +36,7 @@
"createdTime": "2024-03-07T20:28:12.070707" "createdTime": "2024-03-07T20:28:12.070707"
}, },
{ {
"avatar": "https://....jpg", "avatar": "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png",
"id": 21374, "id": 21374,
"op": "宇航员", "op": "宇航员",
"type": 2, "type": 2,
-5
View File
@@ -2,7 +2,6 @@ export default defineAppConfig({
pages: [ pages: [
'pages/index/index', 'pages/index/index',
'pages/repair/repair', 'pages/repair/repair',
'pages/member/member',
'pages/user/user', 'pages/user/user',
'pages/user/myTicket/myTicket', 'pages/user/myTicket/myTicket',
'pages/user/inform/inform', 'pages/user/inform/inform',
@@ -28,10 +27,6 @@ export default defineAppConfig({
pagePath: 'pages/repair/repair', pagePath: 'pages/repair/repair',
text: '维修', text: '维修',
}, },
{
pagePath: 'pages/member/member',
text: '管理',
},
{ {
pagePath: 'pages/user/user', pagePath: 'pages/user/user',
text: '我的', text: '我的',
+18 -2
View File
@@ -2,12 +2,28 @@ import { PropsWithChildren } from 'react';
import { useLaunch } from '@tarojs/taro'; import { useLaunch } from '@tarojs/taro';
import 'taro-ui/dist/style/index.scss'; import 'taro-ui/dist/style/index.scss';
import './app.scss'; import './app.scss';
import { getLocaleData } from './service/localeData'; import { checkLogin, checkToken } from './service/checkLogin';
import wechatUser from './wechat';
import { loginAte } from './service/login';
import { getInfo } from './service/getInfo';
function App({ children }: PropsWithChildren<any>) { function App({ children }: PropsWithChildren<any>) {
useLaunch(() => { useLaunch(() => {
console.log('App launched.'); console.log('App launched.');
getLocaleData(); // if (checkLogin()) {
// wechatUser.setToken(checkToken());
// if(getMemberInfo());
// } else {
// loginAte();
// }
checkLogin((success) => {
if (success) {
wechatUser.setToken(checkToken());
getInfo();
} else {
loginAte();
}
});
}); });
// children 是将要会渲染的页面 // children 是将要会渲染的页面
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1710604932901" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4288" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M512 121.6c217.6 0 390.4 172.8 390.4 390.4S729.6 902.4 512 902.4 121.6 729.6 121.6 512 294.4 121.6 512 121.6m0-89.6C246.4 32 32 249.6 32 512s217.6 480 480 480 480-217.6 480-480S774.4 32 512 32z" p-id="4289"></path><path d="M675.2 512H508.8V284.8c0-25.6-19.2-41.6-41.6-41.6H464c-25.6 0-41.6 19.2-41.6 41.6v272c0 25.6 19.2 41.6 41.6 41.6h214.4c25.6 0 44.8-22.4 44.8-44.8s-22.4-41.6-48-41.6z" p-id="4290"></path></svg>

After

Width:  |  Height:  |  Size: 746 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1710604932901" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4288" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M512 121.6c217.6 0 390.4 172.8 390.4 390.4S729.6 902.4 512 902.4 121.6 729.6 121.6 512 294.4 121.6 512 121.6m0-89.6C246.4 32 32 249.6 32 512s217.6 480 480 480 480-217.6 480-480S774.4 32 512 32z" p-id="4289"></path><path d="M675.2 512H508.8V284.8c0-25.6-19.2-41.6-41.6-41.6H464c-25.6 0-41.6 19.2-41.6 41.6v272c0 25.6 19.2 41.6 41.6 41.6h214.4c25.6 0 44.8-22.4 44.8-44.8s-22.4-41.6-48-41.6z" p-id="4290"></path></svg>

After

Width:  |  Height:  |  Size: 746 B

Before

Width:  |  Height:  |  Size: 710 B

After

Width:  |  Height:  |  Size: 710 B

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1710991023487" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12657" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M512 42.666667q95.658667 0 182.485333 37.162667t149.674667 100.010667 100.010667 149.674667 37.162667 182.485333-37.162667 182.485333-100.010667 149.674667-149.674667 100.010667-182.485333 37.162667-182.485333-37.162667-149.674667-100.010667-100.010667-149.674667-37.162667-182.485333 37.162667-182.485333 100.010667-149.674667 149.674667-100.010667 182.485333-37.162667zM512 128q-77.994667 0-149.162667 30.506667t-122.496 81.834667-81.834667 122.496-30.506667 149.162667 30.506667 149.162667 81.834667 122.496 122.496 81.834667 149.162667 30.506667 149.162667-30.506667 122.496-81.834667 81.834667-122.496 30.506667-149.162667-30.506667-149.162667-81.834667-122.496-122.496-81.834667-149.162667-30.506667zM512 213.333333q17.664 0 30.165333 12.501333t12.501333 30.165333l0 238.336 115.669333 115.328q12.330667 12.330667 12.330667 30.336t-12.330667 30.336-30.336 12.330667-30.336-12.330667l-128-128q-12.330667-12.330667-12.330667-30.336l0-256q0-17.664 12.501333-30.165333t30.165333-12.501333z" fill="#E69966" p-id="12658"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1710991348108" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="26534" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M512 512m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z" p-id="26535" fill="#9ACD32"></path><path d="M712 512m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z" p-id="26536" fill="#9ACD32"></path><path d="M312 512m-48 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0Z" p-id="26537" fill="#9ACD32"></path><path d="M925.2 338.4c-22.6-53.7-55-101.9-96.3-143.3-41.3-41.3-89.5-73.8-143.3-96.3C630.6 75.7 572.2 64 512 64h-2c-60.6 0.3-119.3 12.3-174.5 35.9-53.3 22.8-101.1 55.2-142 96.5-40.9 41.3-73 89.3-95.2 142.8-23 55.4-34.6 114.3-34.3 174.9 0.3 69.4 16.9 138.3 48 199.9v152c0 25.4 20.6 46 46 46h152.1c61.6 31.1 130.5 47.7 199.9 48h2.1c59.9 0 118-11.6 172.7-34.3 53.5-22.3 101.6-54.3 142.8-95.2 41.3-40.9 73.8-88.7 96.5-142 23.6-55.2 35.6-113.9 35.9-174.5 0.3-60.9-11.5-120-34.8-175.6z m-151.1 438C704 845.8 611 884 512 884h-1.7c-60.3-0.3-120.2-15.3-173.1-43.5l-8.4-4.5H188V695.2l-4.5-8.4C155.3 633.9 140.3 574 140 513.7c-0.4-99.7 37.7-193.3 107.6-263.8 69.8-70.5 163.1-109.5 262.8-109.9h1.7c50 0 98.5 9.7 144.2 28.9 44.6 18.7 84.6 45.6 119 80 34.3 34.3 61.3 74.4 80 119 19.4 46.2 29.1 95.2 28.9 145.8-0.6 99.6-39.7 192.9-110.1 262.7z" p-id="26538" fill="#9ACD32"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1710990953433" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11565" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M510 64.4c-246.5 0-447.6 200-447.6 447.6 0 246.5 200 447.6 447.6 447.6 246.5 0 447.6-200 447.6-447.6 0-246.5-200.1-447.6-447.6-447.6z m0 831.9c-212.3 0-384.3-172-384.3-384.3s172-384.3 384.3-384.3 384.3 172 384.3 384.3-172 384.3-384.3 384.3z m229.1-181.2c-18.4-70.4-67.9-125.5-131.2-153.6 48-30.6 79.6-84.2 79.6-144.9 0-94.9-77.1-172-172-172s-172 77.1-172 172c0 61.2 31.6 114.8 79.6 144.9-63.8 27.6-113.3 83.2-131.7 153.6-4.1 16.3 5.6 33.2 21.9 37.3 2.6 0.5 5.1 1 7.7 1 13.8 0 26-9.2 29.6-23 19.4-75 87.3-127.1 164.3-127.1S660 655.4 679.4 730.4c4.1 16.3 20.9 26 37.3 21.9 16.8-4 27-20.9 22.4-37.2zM515.6 305.8c61.2 0 110.7 49.5 110.7 110.7s-49.5 110.7-110.7 110.7-110.7-49.5-110.7-110.7 49.5-110.7 110.7-110.7z" p-id="11566" fill="#78A4FA"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+11 -1
View File
@@ -1 +1,11 @@
export type FixStatus = 1 | 2 | 3 | 4 | 5; export type FixStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export const defaultAvatar =
'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
export const tmplIds = ['hbblqs928F2kd1s0IR_pDIAjYrNscUmz6tv6NZKsctM'];
export type Info = {
phone: string;
name: string;
};
@@ -9,7 +9,6 @@ import {
import pt from '@/plain-text'; import pt from '@/plain-text';
import { RequestState } from '@/service'; import { RequestState } from '@/service';
import { getTicketInfo } from '@/service/ticketsInfo'; import { getTicketInfo } from '@/service/ticketsInfo';
import { FixStatus } from '@/common';
import { AtCard, AtSteps } from 'taro-ui'; import { AtCard, AtSteps } from 'taro-ui';
import NoteList from '../NoteList/NoteList'; import NoteList from '../NoteList/NoteList';
@@ -17,14 +16,6 @@ interface StepItemData {
title: string; title: string;
} }
const mapStatusStep: Map<FixStatus, 0 | 1 | 2 | 3> = new Map([
[1, 0],
[2, 1],
[3, 2],
[4, 2],
[5, 3],
]);
interface DetailFrameworkState { interface DetailFrameworkState {
current: number; current: number;
items: Array<StepItemData>; items: Array<StepItemData>;
@@ -69,6 +60,7 @@ export default class DetailFramework extends Component<
current: true, current: true,
notelist: true, notelist: true,
showAllNotes: true, showAllNotes: true,
info: true,
}, },
}; };
@@ -79,12 +71,6 @@ export default class DetailFramework extends Component<
return <View>Request failed</View>; return <View>Request failed</View>;
} }
const status = this.state.ticketInfo.status;
this.setState({
current: mapStatusStep.get(status) || 0,
items: pt.get().ticketDetail.stepItems,
});
const elements: ShowElements = { const elements: ShowElements = {
device: this.props.isInfoShow['device'] ? ( device: this.props.isInfoShow['device'] ? (
<View className='at-article__h1'> <View className='at-article__h1'>
@@ -103,8 +89,15 @@ export default class DetailFramework extends Component<
<View></View> <View></View>
), ),
description: this.props.isInfoShow['description'] ? ( description: this.props.isInfoShow['description'] ? (
<View style={{ marginTop: 10, marginBottom: 10 }}> <View
<AtCard title={pt.get().ticketDetail.descTitle}> style={{
paddingTop: '20rpx',
paddingBottom: '20rpx',
width: '94%',
marginLeft: '3%',
}}
>
<AtCard isFull title={pt.get().ticketDetail.descTitle}>
<View className='at-article__h3'> <View className='at-article__h3'>
{this.state.ticketInfo.description} {this.state.ticketInfo.description}
</View> </View>
@@ -113,8 +106,36 @@ export default class DetailFramework extends Component<
) : ( ) : (
<View></View> <View></View>
), ),
info: this.props.isInfoShow['info'] ? (
<View
style={{
paddingTop: '20rpx',
paddingBottom: '20rpx',
width: '94%',
marginLeft: '3%',
}}
>
<AtCard
isFull
title={pt.get().ticketDetail.info.title}
extra={pt.get().ticketDetail.info.extra}
extraStyle={{ fontSize: '32rpx', marginRight: '40rpx' }}
>
<View style={{ display: 'flex' }}>
<View className='at-article__h3'>
{this.state.ticketInfo.info.name}
</View>
<View style={{ marginLeft: 'auto' }} className='at-article__h3'>
{this.state.ticketInfo.info.phone}
</View>
</View>
</AtCard>
</View>
) : (
<View></View>
),
current: this.props.isInfoShow['current'] ? ( current: this.props.isInfoShow['current'] ? (
<View style={{ padding: 10 }}> <View style={{ padding: '20rpx' }}>
<AtSteps <AtSteps
items={this.state.items} items={this.state.items}
current={this.state.current} current={this.state.current}
@@ -126,11 +147,11 @@ export default class DetailFramework extends Component<
), ),
notelist: this.props.isInfoShow['notelist'] ? ( notelist: this.props.isInfoShow['notelist'] ? (
this.props.isInfoShow['showAllNotes'] ? ( this.props.isInfoShow['showAllNotes'] ? (
<View style={{ padding: 10 }}> <View style={{ padding: '20rpx' }}>
<NoteList noteList={this.state.notes} /> <NoteList noteList={this.state.notes} />
</View> </View>
) : ( ) : (
<View style={{ padding: 10 }}> <View style={{ padding: '20rpx' }}>
<NoteList <NoteList
noteList={[this.state.notes[this.state.notes.length - 1]]} noteList={[this.state.notes[this.state.notes.length - 1]]}
/> />
@@ -146,6 +167,7 @@ export default class DetailFramework extends Component<
{elements.device} {elements.device}
{elements.createdTime} {elements.createdTime}
{elements.description} {elements.description}
{elements.info}
{elements.current} {elements.current}
{this.props.middleButton} {this.props.middleButton}
{elements.notelist} {elements.notelist}
+18 -8
View File
@@ -1,9 +1,8 @@
import { View } from '@tarojs/components'; import { Image, View } from '@tarojs/components';
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import { TicketNote, StatusStr } from '@/pages/TicketDetail/TicketNote'; import { TicketNote, StatusStr } from '@/pages/TicketDetail/TicketNote';
import pt from '@/plain-text'; import pt from '@/plain-text';
import { timeFormat } from '@/utils'; import { timeFormat } from '@/utils';
import { AtDivider } from 'taro-ui';
import './NoteCard.scss'; import './NoteCard.scss';
interface NoteCardProps { interface NoteCardProps {
@@ -36,13 +35,24 @@ export default class NoteCard extends Component<NoteCardProps, {}> {
} }
return ( return (
<View> <View className='at-row at-row__align--center'>
<View className='at-article__h2'>{note.op}</View> <View className='at-col at-col-1 at-col--auto'>
<View className='at-article__info'> <Image
{note.createdTime.format(timeFormat)} style='width: 70rpx; height: 70rpx; border-radius: 35px;'
src={note.avatar}
mode='aspectFit'
/>
</View>
<View
className='at-col'
style={{ marginTop: '40rpx', marginBottom: '40rpx' }}
>
<View className='at-article__p'>{note.op}</View>
<View className='at-article__info'>
{note.createdTime.format(timeFormat)}
</View>
<View className='at-article__h3'>{message}</View>
</View> </View>
<View className='at-article__p'>{message}</View>
<AtDivider />
</View> </View>
); );
} }
+7
View File
@@ -2,6 +2,8 @@ import { Component, ReactNode } from 'react';
import NoteCard from '@/components/NoteCard/NoteCard'; import NoteCard from '@/components/NoteCard/NoteCard';
import { TicketNote } from '@/pages/TicketDetail/TicketNote'; import { TicketNote } from '@/pages/TicketDetail/TicketNote';
import { View } from '@tarojs/components'; import { View } from '@tarojs/components';
import { AtDivider } from 'taro-ui';
import pt from '@/plain-text';
interface NoteListProps { interface NoteListProps {
noteList: Array<TicketNote>; noteList: Array<TicketNote>;
@@ -14,6 +16,11 @@ export default class NoteList extends Component<NoteListProps, {}> {
render(): ReactNode { render(): ReactNode {
return ( return (
<View> <View>
<AtDivider
fontColor='#CCC'
content={pt.get().ticketDetail.divider}
height={20}
/>
{this.props.noteList.map((note, idx) => ( {this.props.noteList.map((note, idx) => (
<View key={idx}> <View key={idx}>
<NoteCard note={note} /> <NoteCard note={note} />
+3 -3
View File
@@ -3,8 +3,8 @@ import { AtDivider } from 'taro-ui';
import pt from '@/plain-text'; import pt from '@/plain-text';
export default () => { export default () => {
const blankHeightUpper = 15; const blankHeightUpper = '30rpx';
const blankHeightLower = 110; const blankHeightLower = '220rpx';
return ( return (
<View> <View>
<View style={{ height: blankHeightUpper }}></View> <View style={{ height: blankHeightUpper }}></View>
@@ -16,7 +16,7 @@ export default () => {
/> />
</View> </View>
<View className='at-row at-row__justify--center'> <View className='at-row at-row__justify--center'>
<Text style='color:#dddddd;'>© 2024 EVA Tech</Text> <Text style='color:#dddddd; fontSize:32rpx'>© 2024 EVA Tech</Text>
</View> </View>
<View style={{ height: blankHeightLower }}></View> <View style={{ height: blankHeightLower }}></View>
</View> </View>
@@ -3,10 +3,10 @@ import repair from '@/assets/icons/MyTickets/repair.svg';
import finished from '@/assets/icons/MyTickets/finished.svg'; import finished from '@/assets/icons/MyTickets/finished.svg';
import tick from '@/assets/icons/MyTickets/tick.svg'; import tick from '@/assets/icons/MyTickets/tick.svg';
import fail from '@/assets/icons/MyTickets/fail.svg'; import fail from '@/assets/icons/MyTickets/fail.svg';
import clock from '@/assets/icons/MyTickets/clock.svg';
import pt from '@/plain-text'; import pt from '@/plain-text';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import { FixStatus } from '@/common';
type FixStatus = 1 | 2 | 3 | 4 | 5;
export class TicketListItem { export class TicketListItem {
id: number; id: number;
@@ -29,11 +29,14 @@ export class TicketListItem {
this.status = status; this.status = status;
this.createAt = createAt; this.createAt = createAt;
this.iconMap = new Map<FixStatus, string>([ this.iconMap = new Map<FixStatus, string>([
[0, repair],
[1, repair], [1, repair],
[2, repair], [2, clock],
[3, finished], [3, finished],
[4, tick], [4, clock],
[5, fail], [5, tick],
[6, clock],
[7, fail],
]); ]);
} }
+50 -53
View File
@@ -6,65 +6,62 @@ import wechatUser from '@/wechat';
import 'taro-ui/dist/style/index.scss'; import 'taro-ui/dist/style/index.scss';
import './index.scss'; import './index.scss';
const navList: Array<Taro.TabBarItem> = [ const navList: () => Array<Taro.TabBarItem> = () => {
{ return [
pagePath: '/pages/index/index', {
text: pt.get().tabBar.indexText, pagePath: '/pages/index/index',
}, text: pt.get().tabBar.indexText,
{ },
pagePath: '/pages/repair/repair', {
text: pt.get().tabBar.repairText, pagePath: '/pages/repair/repair',
}, text: pt.get().tabBar.repairText,
{ },
pagePath: '/pages/member/member', {
text: pt.get().tabBar.memberText, pagePath: '/pages/user/user',
}, text: pt.get().tabBar.userText,
{ },
pagePath: '/pages/user/user', ];
text: pt.get().tabBar.userText, };
},
]; const tabList = () => {
return wechatUser.getAccess()
? [
{
title: pt.get().tabBar.memberText,
iconType: 'sketch',
},
{
title: pt.get().tabBar.repairText,
iconType: 'settings',
},
{
title: pt.get().tabBar.userText,
iconType: 'user',
},
]
: [
{
title: pt.get().tabBar.indexText,
iconType: 'home',
},
{
title: pt.get().tabBar.repairText,
iconType: 'settings',
},
{
title: pt.get().tabBar.userText,
iconType: 'user',
},
];
};
export default class Index extends Component { export default class Index extends Component {
state = { state = {
selected: 0, selected: 0,
tabList: wechatUser.getAccess()
? [
{
title: pt.get().tabBar.indexText,
iconType: 'home',
},
{
title: pt.get().tabBar.repairText,
iconType: 'settings',
},
{
title: pt.get().tabBar.memberText,
iconType: 'sketch',
},
{
title: pt.get().tabBar.userText,
iconType: 'user',
},
]
: [
{
title: pt.get().tabBar.indexText,
iconType: 'home',
},
{
title: pt.get().tabBar.repairText,
iconType: 'settings',
},
{
title: pt.get().tabBar.userText,
iconType: 'user',
},
],
}; };
handleClick(idx: number) { handleClick(idx: number) {
this.switchTab(idx, navList[idx].pagePath); this.switchTab(idx, navList()[idx].pagePath);
} }
switchTab(idx: number, url: string) { switchTab(idx: number, url: string) {
@@ -82,7 +79,7 @@ export default class Index extends Component {
return ( return (
<AtTabBar <AtTabBar
fixed fixed
tabList={this.state.tabList} tabList={tabList()}
onClick={this.handleClick.bind(this)} onClick={this.handleClick.bind(this)}
current={this.state.selected} current={this.state.selected}
/> />
+386 -7
View File
@@ -2,17 +2,78 @@ import { Component, ReactNode } from 'react';
import { View } from '@tarojs/components'; import { View } from '@tarojs/components';
import { getCurrentInstance } from '@tarojs/runtime'; import { getCurrentInstance } from '@tarojs/runtime';
import pt from '@/plain-text'; import pt from '@/plain-text';
import { AtButton } from 'taro-ui'; import {
AtActionSheet,
AtActionSheetItem,
AtButton,
AtFloatLayout,
AtForm,
AtMessage,
AtModal,
AtTextarea,
} from 'taro-ui';
import DetailFramework from '@/components/DetailFramework/DetailFramework'; import DetailFramework from '@/components/DetailFramework/DetailFramework';
import PageFooter from '@/components/PageFooter/PageFooter'; import PageFooter from '@/components/PageFooter/PageFooter';
import { submitComment } from '@/service/submitComment';
import Taro from '@tarojs/taro';
import wechatUser from '@/wechat';
import { addToOreo } from '@/service/addToOreo';
import { pickTicket } from '@/service/pickTicket';
import { retrieve } from '@/service/retrieve';
import { changeStatus } from '@/service/changeStatus';
import { getDisable } from '@/service/getDisable';
const submitInterval = 5000;
interface TicketDetailState { interface TicketDetailState {
id: number; id: number;
isMember: boolean;
showOreoModal: boolean;
showCommentLayout: boolean;
showRetrieveModal: boolean;
showStatusSheet: boolean;
showPickModal: boolean;
comment: string;
isOreoLoading: boolean;
isOreoDisable: boolean;
isOreoDisable_main: boolean;
isPickLoading: boolean;
isPickDisable: boolean;
isPickDisable_main: boolean;
isRetrieveLoading: boolean;
isRetrieveDisable: boolean;
isRetrieveDisable_main: boolean;
isStatusLoading: boolean;
isStatusDisable: boolean;
isCommentLoading: boolean;
isCommentDisable: boolean;
isCommentDisable_main: boolean;
} }
export default class TicketDetail extends Component<{}, TicketDetailState> { export default class TicketDetail extends Component<{}, TicketDetailState> {
state: Readonly<TicketDetailState> = { state: Readonly<TicketDetailState> = {
id: 0, id: 0,
isMember: false,
showOreoModal: false,
showCommentLayout: false,
showRetrieveModal: false,
showStatusSheet: false,
showPickModal: false,
comment: '',
isOreoLoading: false,
isOreoDisable: false,
isOreoDisable_main: false,
isPickLoading: false,
isPickDisable: false,
isPickDisable_main: false,
isRetrieveLoading: false,
isRetrieveDisable: false,
isRetrieveDisable_main: false,
isStatusLoading: false,
isStatusDisable: false,
isCommentLoading: false,
isCommentDisable: false,
isCommentDisable_main: false,
}; };
componentDidMount(): void { componentDidMount(): void {
@@ -20,26 +81,265 @@ export default class TicketDetail extends Component<{}, TicketDetailState> {
const id = router?.params.id as number; const id = router?.params.id as number;
this.setState({ this.setState({
id: id, id: id,
isMember: wechatUser.getAccess(),
});
getDisable(this, id);
}
onAddToOreo(): void {
this.setState({
showOreoModal: true,
}); });
} }
onAddComment(): void {
this.setState({
showCommentLayout: true,
});
}
onRetrieved(): void {
this.setState({
showRetrieveModal: true,
});
}
onPick(): void {
this.setState({
showPickModal: true,
});
}
onChangeStatus(): void {
this.setState({
showStatusSheet: true,
});
}
handleOreoCancel(): void {
this.setState({
showOreoModal: false,
});
}
handleCommentCancel(): void {
this.setState({
showCommentLayout: false,
});
}
handleRetrieveCancel(): void {
this.setState({
showRetrieveModal: false,
});
}
handleStatusCancel(): void {
this.setState({
showStatusSheet: false,
});
}
handlePickCancel(): void {
this.setState({
showPickModal: false,
});
}
handleOreoConfirm(): void {
this.setState({
isOreoDisable: true,
showOreoModal: false,
});
addToOreo(this);
setTimeout(() => {
this.setState({
isOreoDisable: false,
});
}, submitInterval);
return;
}
handleRetrieveConfirm(): void {
this.setState({
isRetrieveDisable: true,
showRetrieveModal: false,
});
retrieve(this);
setTimeout(() => {
this.setState({
isRetrieveDisable: false,
});
}, submitInterval);
return;
}
handlePickConfirm(): void {
this.setState({
isPickDisable: true,
showPickModal: false,
});
pickTicket(this);
setTimeout(() => {
this.setState({
isPickDisable: false,
});
}, submitInterval);
return;
}
handleStatusChange(status: number): void {
this.setState({
showStatusSheet: false,
isStatusDisable: true,
});
changeStatus(this, status);
setTimeout(() => {
this.setState({
isStatusDisable: false,
});
}, submitInterval);
return;
}
handleCommentChange(comment: string) {
this.setState({
comment: comment,
});
return comment;
}
onCommentSubmit() {
this.setState({
isCommentDisable: true,
showCommentLayout: false,
});
if (this.state.comment == '') {
Taro.atMessage({
message: pt.get().button.submitText.blank,
type: 'error',
});
setTimeout(() => {
this.setState({
isCommentDisable: false,
});
}, submitInterval);
return;
}
submitComment(this);
setTimeout(() => {
this.setState({
isCommentDisable: false,
});
}, submitInterval);
}
render(): ReactNode { render(): ReactNode {
const middleButton = ( const middleButton = this.state.isMember ? (
<View>
<View
className='at-row'
style={{ paddingTop: '20rpx', paddingBottom: '20rpx', width: '100%' }}
>
<View
className='at-col'
style={{ marginLeft: '20rpx', paddingRight: '10rpx', width: '50%' }}
>
<AtButton
loading={this.state.isPickLoading}
disabled={
this.state.isPickDisable || this.state.isPickDisable_main
}
type='secondary'
onClick={this.onPick.bind(this)}
>
{pt.get().ticketDetail.pick}
</AtButton>
</View>
<View
className='at-col'
style={{ marginLeft: '20rpx', paddingRight: '10rpx', width: '50%' }}
>
<AtButton
loading={this.state.isOreoLoading}
disabled={
this.state.isOreoDisable || this.state.isOreoDisable_main
}
type='primary'
onClick={this.onAddToOreo.bind(this)}
>
{pt.get().ticketDetail.addToOreo}
</AtButton>
</View>
</View>
<View
className='at-row'
style={{ paddingTop: '20rpx', paddingBottom: '40rpx', width: '100%' }}
>
<View
className='at-col'
style={{ marginLeft: '20rpx', paddingRight: '10rpx', width: '50%' }}
>
<AtButton
loading={this.state.isStatusLoading}
disabled={this.state.isStatusDisable}
type='primary'
onClick={this.onChangeStatus.bind(this)}
>
{pt.get().ticketDetail.status.button}
</AtButton>
</View>
<View
className='at-col'
style={{ marginLeft: '20rpx', paddingRight: '10rpx', width: '50%' }}
>
<AtButton
disabled={
this.state.isCommentDisable || this.state.isCommentDisable_main
}
loading={this.state.isCommentLoading}
type='secondary'
onClick={this.onAddComment.bind(this)}
>
{pt.get().ticketDetail.addNote}
</AtButton>
</View>
</View>
</View>
) : (
<View <View
className='at-row' className='at-row'
style={{ paddingTop: 10, paddingBottom: 10, width: '100%' }} style={{ paddingTop: '20rpx', paddingBottom: '40rpx', width: '100%' }}
> >
<View <View
className='at-col' className='at-col'
style={{ marginLeft: 10, paddingRight: 5, width: '50%' }} style={{ marginLeft: '20rpx', paddingRight: '10rpx', width: '50%' }}
> >
<AtButton type='primary'>{pt.get().ticketDetail.tookAway}</AtButton> <AtButton
loading={this.state.isRetrieveLoading}
disabled={
this.state.isRetrieveDisable || this.state.isRetrieveDisable_main
}
type='primary'
onClick={this.onRetrieved.bind(this)}
>
{pt.get().ticketDetail.tookAway}
</AtButton>
</View> </View>
<View <View
className='at-col' className='at-col'
style={{ marginRight: 10, paddingLeft: 5, width: '50%' }} style={{ marginRight: '20rpx', paddingLeft: '10rpx', width: '50%' }}
> >
<AtButton type='secondary'>{pt.get().ticketDetail.addNote}</AtButton> <AtButton
disabled={
this.state.isCommentDisable || this.state.isCommentDisable_main
}
loading={this.state.isCommentLoading}
type='secondary'
onClick={this.onAddComment.bind(this)}
>
{pt.get().ticketDetail.addNote}
</AtButton>
</View> </View>
</View> </View>
); );
@@ -48,6 +348,7 @@ export default class TicketDetail extends Component<{}, TicketDetailState> {
device: true, device: true,
createdTime: true, createdTime: true,
description: true, description: true,
info: wechatUser.getAccess() ? true : false,
current: true, current: true,
notelist: true, notelist: true,
showAllNotes: true, showAllNotes: true,
@@ -55,6 +356,84 @@ export default class TicketDetail extends Component<{}, TicketDetailState> {
return ( return (
<View> <View>
<AtMessage />
<AtModal
isOpened={this.state.showOreoModal}
title={pt.get().modal.addToOreo.title}
cancelText={pt.get().modal.cancel}
confirmText={pt.get().modal.confirm}
onCancel={this.handleOreoCancel.bind(this)}
onConfirm={this.handleOreoConfirm.bind(this)}
content={pt.get().modal.addToOreo.content}
/>
<AtModal
isOpened={this.state.showRetrieveModal}
title={pt.get().modal.retrieve.title}
cancelText={pt.get().modal.cancel}
confirmText={pt.get().modal.confirm}
onCancel={this.handleRetrieveCancel.bind(this)}
onConfirm={this.handleRetrieveConfirm.bind(this)}
content={pt.get().modal.retrieve.content}
/>
<AtModal
isOpened={this.state.showPickModal}
title={pt.get().modal.pick.title}
cancelText={pt.get().modal.cancel}
confirmText={pt.get().modal.confirm}
onCancel={this.handlePickCancel.bind(this)}
onConfirm={this.handlePickConfirm.bind(this)}
content={pt.get().modal.pick.content}
/>
<AtFloatLayout
isOpened={this.state.showCommentLayout}
title={pt.get().ticketDetail.comment.title}
onClose={this.handleCommentCancel.bind(this)}
>
<AtForm onSubmit={this.onCommentSubmit.bind(this)}>
<AtTextarea
value={this.state.comment}
onChange={this.handleCommentChange.bind(this)}
maxLength={200}
height='400rpx'
placeholder={pt.get().ticketDetail.comment.placeholder}
/>
<AtButton formType='submit' type='primary'>
{pt.get().button.buttonText.submit}
</AtButton>
</AtForm>
</AtFloatLayout>
<AtActionSheet
isOpened={this.state.showStatusSheet}
cancelText={pt.get().ticketDetail.status.cancel}
title={pt.get().ticketDetail.status.title}
onCancel={this.handleStatusCancel.bind(this)}
onClose={this.handleStatusCancel.bind(this)}
>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 0)}>
{pt.get().ticketDetail.status.status0}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 1)}>
{pt.get().ticketDetail.status.status1}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 2)}>
{pt.get().ticketDetail.status.status2}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 3)}>
{pt.get().ticketDetail.status.status3}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 4)}>
{pt.get().ticketDetail.status.status4}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 5)}>
{pt.get().ticketDetail.status.status5}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 6)}>
{pt.get().ticketDetail.status.status6}
</AtActionSheetItem>
<AtActionSheetItem onClick={this.handleStatusChange.bind(this, 7)}>
{pt.get().ticketDetail.status.status7}
</AtActionSheetItem>
</AtActionSheet>
<DetailFramework <DetailFramework
middleButton={middleButton} middleButton={middleButton}
id={this.state.id} id={this.state.id}
+5 -1
View File
@@ -1,4 +1,4 @@
import { FixStatus } from '@/common'; import { FixStatus, Info } from '@/common';
export class TicketInfo { export class TicketInfo {
id: number; id: number;
@@ -8,9 +8,12 @@ export class TicketInfo {
description: string; description: string;
createdTime: moment.Moment; createdTime: moment.Moment;
status: FixStatus; status: FixStatus;
info: Info;
workers: string[];
} }
export class TicketNote { export class TicketNote {
avatar: string;
id: number; id: number;
op: string; op: string;
type: 0 | 1 | 2; type: 0 | 1 | 2;
@@ -22,6 +25,7 @@ export class ShowElements {
device: JSX.Element; device: JSX.Element;
createdTime: JSX.Element; createdTime: JSX.Element;
description: JSX.Element; description: JSX.Element;
info: JSX.Element;
current: JSX.Element; current: JSX.Element;
notelist: JSX.Element; notelist: JSX.Element;
} }
+21 -10
View File
@@ -4,6 +4,8 @@ import { AtTimeline } from 'taro-ui';
import pt from '@/plain-text'; import pt from '@/plain-text';
import tick from '@/assets/icons/MainPage/tick.svg'; import tick from '@/assets/icons/MainPage/tick.svg';
import cross from '@/assets/icons/MainPage/cross.svg'; import cross from '@/assets/icons/MainPage/cross.svg';
import clock from '@/assets/icons/MemberPage/clock.svg';
import wechatUser from '@/wechat';
export class DutyData { export class DutyData {
constructor() { constructor() {
@@ -12,48 +14,52 @@ export class DutyData {
this.currentDuty = '2'; this.currentDuty = '2';
this.offDutyReason = '学园维修'; this.offDutyReason = '学园维修';
this.dutyRecoverTime = '下周一'; this.dutyRecoverTime = '下周一';
this.place = '东三-204';
} }
isInDuty: boolean; isInDuty: boolean;
inDutyCnt?: number; inDutyCnt?: number;
currentDuty?: 'off' | '1' | '2' | '3'; currentDuty?: 'off' | '1' | '2' | '3' | 'others';
offDutyReason?: string; offDutyReason?: string;
dutyRecoverTime?: string; dutyRecoverTime?: string;
place: string;
} }
class Card extends Component { class Card extends Component {
props = { props = {
isInDuty: false, isInDuty: false,
place: '东三-204',
}; };
render(): ReactNode { render(): ReactNode {
const inDuty = this.props.isInDuty; const inDuty = this.props.isInDuty;
const place = this.props.place;
const dc = pt.get().mainPage.dutyCard; const dc = pt.get().mainPage.dutyCard;
const title = inDuty ? dc.inDuty.title : dc.offDuty.title; const title = inDuty ? dc.inDuty.title : dc.offDuty.title;
const iconsrc = inDuty ? tick : cross; const iconsrc = inDuty ? tick : wechatUser.getAccess() ? clock : cross;
return ( return (
<View> <View>
<View <View
style={{ style={{
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
marginBottom: 20, marginBottom: '40rpx',
}} }}
> >
<Image <Image
src={iconsrc} src={iconsrc}
style={{ style={{
width: 24, width: '48rpx',
height: 24, height: '48rpx',
}} }}
/> />
<View <View
style={{ style={{
marginLeft: 10, marginLeft: '20rpx',
fontSize: 30, fontSize: '60rpx',
fontWeight: 'bold', fontWeight: 'bold',
}} }}
> >
{title} {'[' + place + '] ' + title}
</View> </View>
</View> </View>
</View> </View>
@@ -62,6 +68,11 @@ class Card extends Component {
} }
export class DutyInfo extends Component { export class DutyInfo extends Component {
state: {
isLoading: false;
isDisable: false;
};
props = { props = {
data: new DutyData(), data: new DutyData(),
}; };
@@ -71,7 +82,7 @@ export class DutyInfo extends Component {
const od = pt.get().mainPage.dutyCard.offDuty; const od = pt.get().mainPage.dutyCard.offDuty;
return ( return (
<View> <View>
<Card isInDuty={data.isInDuty} /> <Card isInDuty={data.isInDuty} place={data.place} />
<AtTimeline <AtTimeline
items={[ items={[
{ title: od.reason(data.offDutyReason as string) }, { title: od.reason(data.offDutyReason as string) },
@@ -87,7 +98,7 @@ export class DutyInfo extends Component {
const id = pt.get().mainPage.dutyCard.inDuty; const id = pt.get().mainPage.dutyCard.inDuty;
return ( return (
<View> <View>
<Card isInDuty={data.isInDuty} /> <Card isInDuty={data.isInDuty} place={data.place} />
<AtTimeline <AtTimeline
items={[ items={[
{ title: id.currentDutyText(data.currentDuty || 'off') }, { title: id.currentDutyText(data.currentDuty || 'off') },
+15 -2
View File
@@ -2,12 +2,19 @@ import { Component, ReactNode } from 'react';
import { View } from '@tarojs/components'; import { View } from '@tarojs/components';
import { AtTimeline } from 'taro-ui'; import { AtTimeline } from 'taro-ui';
import pt from '@/plain-text'; import pt from '@/plain-text';
import wechatUser from '@/wechat';
export class StepInfo extends Component { export class StepInfo extends Component {
render(): ReactNode { render(): ReactNode {
return ( return (
<View> <View>
<AtTimeline items={pt.get().mainPage.stepList}></AtTimeline> <AtTimeline
items={
wechatUser.getAccess()
? pt.get().memberPage.stepList
: pt.get().mainPage.stepList
}
></AtTimeline>
</View> </View>
); );
} }
@@ -17,7 +24,13 @@ export class TipsInfo extends Component {
render(): ReactNode { render(): ReactNode {
return ( return (
<View> <View>
<AtTimeline items={pt.get().mainPage.tipsList}></AtTimeline> <AtTimeline
items={
wechatUser.getAccess()
? pt.get().memberPage.tipsList
: pt.get().mainPage.tipsList
}
></AtTimeline>
</View> </View>
); );
} }
+12 -4
View File
@@ -2,24 +2,32 @@ import React from 'react';
import { View, Image } from '@tarojs/components'; import { View, Image } from '@tarojs/components';
import pt from '@/plain-text'; import pt from '@/plain-text';
import logo from '@/assets/images/UserPage/logo.png'; import logo from '@/assets/images/UserPage/logo.png';
import wechatUser from '@/wechat';
export default class TitleCard extends React.Component { export default class TitleCard extends React.Component {
render(): React.ReactNode { render(): React.ReactNode {
const mainPage = pt.get().mainPage; const mainPage = pt.get().mainPage;
const memberPage = pt.get().memberPage;
return ( return (
<View className='at-row at-row__align--center'> <View className='at-row at-row__align--center'>
<View className='at-col at-col-1 at-col--auto'> <View className='at-col at-col-1 at-col--auto'>
<Image <Image
style='width: 50px; height: 50px; margin-left: 15px;' style='width: 100rpx; height: 100rpx; margin-left: 30rpx;'
src={logo} src={wechatUser.getAccess() ? wechatUser.getInfo().avatar : logo}
mode='aspectFit' mode='aspectFit'
/> />
</View> </View>
<View className='page-title'> <View className='page-title'>
<View className='at-article__h1' style={{ fontWeight: 'bold' }}> <View className='at-article__h1' style={{ fontWeight: 'bold' }}>
{mainPage.mainTitleLine} {wechatUser.getAccess()
? memberPage.mainTitleLine + wechatUser.getInfo().name
: mainPage.mainTitleLine}
</View>
<View className='at-article__h2'>
{wechatUser.getAccess()
? memberPage.subTitleLine
: mainPage.subTitleLine}
</View> </View>
<View className='at-article__h2'>{mainPage.subTitleLine}</View>
</View> </View>
</View> </View>
); );
+156 -25
View File
@@ -1,16 +1,25 @@
import { View } from '@tarojs/components'; import { View } from '@tarojs/components';
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import { AtCard, AtAccordion } from 'taro-ui'; import { AtCard, AtAccordion, AtInputNumber, AtButton, AtList } from 'taro-ui';
import type CustomTabBar from '@/custom-tab-bar'; import type CustomTabBar from '@/custom-tab-bar';
import PageFooter from '@/components/PageFooter/PageFooter'; import PageFooter from '@/components/PageFooter/PageFooter';
import pt from '@/plain-text'; import pt from '@/plain-text';
import { getDutyInfo } from '@/service/dutyInfo'; import { getDutyInfo } from '@/service/dutyInfo';
import { RequestState } from '@/service';
import moment from 'moment';
import wechatUser from '@/wechat';
import { getMemberDutyInfo } from '@/service/memberDutyInfo';
import { getUncompletedTicketList } from '@/service/uncompletedTicket';
import { changeDutyCnt } from '@/service/changeDutyCount';
import { TicketListItem } from '@/components/TicketListItem/TicketListItem';
import './index.scss'; import './index.scss';
import TitleCard from './TitleCard'; import TitleCard from './TitleCard';
import { DutyInfo, DutyData } from './DutyInfo'; import { DutyInfo, DutyData } from './DutyInfo';
import { StepInfo, TipsInfo } from './StepTipsInfo'; import { StepInfo, TipsInfo } from './StepTipsInfo';
const submitInterval = 5000;
class CardContent { class CardContent {
title: string; title: string;
note: string; note: string;
@@ -20,7 +29,7 @@ class CardContent {
function mainPageCard(c: CardContent): JSX.Element { function mainPageCard(c: CardContent): JSX.Element {
return ( return (
<View style={{ marginTop: 10 }}> <View style={{ marginTop: '20rpx', marginBottom: '40rpx' }}>
<AtCard note={c.note} extra={c.extra} title={c.title}> <AtCard note={c.note} extra={c.extra} title={c.title}>
{c.content()} {c.content()}
</AtCard> </AtCard>
@@ -57,39 +66,77 @@ class ExpandItem extends Component {
} }
interface MainPageState { interface MainPageState {
fixList: Array<TicketListItem>;
rs: RequestState;
dutyData: DutyData; dutyData: DutyData;
inDutyCnt: number;
dutyInfoCard: CardContent; dutyInfoCard: CardContent;
stepInfoCard: CardContent; stepInfoCard: CardContent;
tipsInfoCard: CardContent; tipsInfoCard: CardContent;
//rs: RequestState; isLoading: boolean;
isDisable: boolean;
} }
export default class MainPage extends Component<{}, MainPageState> { export default class MainPage extends Component<{}, MainPageState> {
state = { state = {
dutyData: new DutyData(), dutyData: new DutyData(),
inDutyCnt: 0,
dutyInfoCard: { dutyInfoCard: {
title: pt.get().mainPage.cardTitle.dutyInfo, title: '',
note: pt.get().mainPage.cardTips.dutyInfo, note: '',
extra: pt.get().mainPage.extraInfo.dutyInfo, extra: '',
content: () => <DutyInfo data={this.state.dutyData} />, content: () => <></>,
}, },
stepInfoCard: { stepInfoCard: {
title: pt.get().mainPage.cardTitle.stepInfo, title: '',
note: pt.get().mainPage.cardTips.stepInfo, note: '',
extra: pt.get().mainPage.extraInfo.dutyInfo, extra: '',
content: () => <StepInfo />, content: () => <></>,
}, },
tipsInfoCard: { tipsInfoCard: {
title: pt.get().mainPage.cardTitle.tipsInfo, title: '',
note: pt.get().mainPage.cardTips.tipsInfo, note: '',
extra: pt.get().mainPage.extraInfo.dutyInfo, extra: '',
content: () => <TipsInfo />, content: () => <></>,
}, },
// rs: new RequestState(), fixList: [new TicketListItem(0, '', '', 1, moment())],
rs: new RequestState(),
isLoading: false,
isDisable: false,
}; };
componentDidMount(): void { componentDidMount(): void {
getDutyInfo(this); const ptPage = wechatUser.getAccess() ? 'mainPage' : 'memberPage';
this.setState({
dutyData: new DutyData(),
inDutyCnt: 0,
dutyInfoCard: {
title: pt.get()[ptPage].cardTitle.dutyInfo,
note: pt.get()[ptPage].cardTips.dutyInfo,
extra: pt.get()[ptPage].extraInfo.dutyInfo,
content: () => <DutyInfo data={this.state.dutyData} />,
},
stepInfoCard: {
title: pt.get()[ptPage].cardTitle.stepInfo,
note: pt.get()[ptPage].cardTips.stepInfo,
extra: pt.get()[ptPage].extraInfo.dutyInfo,
content: () => <StepInfo />,
},
tipsInfoCard: {
title: pt.get()[ptPage].cardTitle.tipsInfo,
note: pt.get()[ptPage].cardTips.tipsInfo,
extra: pt.get()[ptPage].extraInfo.dutyInfo,
content: () => <TipsInfo />,
},
});
if (wechatUser.getAccess()) {
getMemberDutyInfo(this);
getUncompletedTicketList(this);
} else {
getDutyInfo(this);
}
} }
// 以下是TabBar相关 // 以下是TabBar相关
@@ -100,20 +147,104 @@ export default class MainPage extends Component<{}, MainPageState> {
} }
// 以上是TabBar相关 // 以上是TabBar相关
handleCnt(inDutyCnt: number) {
this.setState({
inDutyCnt: inDutyCnt,
});
return inDutyCnt;
}
onChangeCnt() {
this.setState({
isDisable: true,
});
changeDutyCnt(this);
setTimeout(() => {
this.setState({
isDisable: false,
});
}, submitInterval);
}
render(): ReactNode { render(): ReactNode {
const mainPage = pt.get().mainPage; const mainPage = pt.get().mainPage;
const memberPage = pt.get().memberPage;
if (this.state.rs.loading) {
return <View>loading</View>;
}
if (!this.state.rs.success) {
return <View>Failed</View>;
}
const fixListRenderer = this.state.fixList.map((item) => item.render());
return ( return (
<View> <View>
<TitleCard /> <TitleCard />
<View style={{ marginTop: 30 }}> <View style={{ width: '94%', marginLeft: '3%' }}>
{mainPageCard(this.state.dutyInfoCard)} <View style={{ marginTop: '60rpx' }}>
{mainPageCard(this.state.tipsInfoCard)} {mainPageCard(this.state.dutyInfoCard)}
<ExpandItem {mainPageCard(this.state.tipsInfoCard)}
title={mainPage.expandTitle.stepInfo} {wechatUser.getAccess() && this.state.dutyData.isInDuty ? (
content={mainPageCard(this.state.stepInfoCard)} <ExpandItem
/> title={memberPage.expandTitle.admin}
content={
<View
style={{
display: 'flex',
alignItems: 'center',
marginBottom: '40rpx',
}}
>
<View
className='.at-article__h3'
style={{
marginTop: '40rpx',
}}
>
{pt.get().memberPage.dutyCount.text}
</View>
<View
style={{
marginTop: '40rpx',
}}
>
<AtInputNumber
type='number'
min={0}
max={10}
step={1}
value={this.state.inDutyCnt}
onChange={this.handleCnt.bind(this)}
/>
</View>
<View style={{ marginLeft: 'auto', marginTop: '40rpx' }}>
<AtButton
type='secondary'
size='small'
loading={this.state.isLoading}
disabled={this.state.isDisable}
onClick={this.onChangeCnt.bind(this)}
>
{pt.get().memberPage.dutyCount.button}
</AtButton>
</View>
</View>
}
/>
) : (
<View></View>
)}
<ExpandItem
title={mainPage.expandTitle.stepInfo}
content={mainPageCard(this.state.stepInfoCard)}
/>
</View>
{wechatUser.getAccess() ? (
<AtList>{fixListRenderer}</AtList>
) : (
<View></View>
)}
<PageFooter />
</View> </View>
<PageFooter />
</View> </View>
); );
} }
-3
View File
@@ -1,3 +0,0 @@
export default definePageConfig({
usingComponents: {},
});
View File
-23
View File
@@ -1,23 +0,0 @@
import { View, Text } from '@tarojs/components';
import { Component, ReactNode } from 'react';
import Taro from '@tarojs/taro';
import type CustomTabBar from '../../custom-tab-bar';
import './member.scss';
export default class MemberPage extends Component {
// 以下是TabBar相关
pageCtx = Taro.getCurrentInstance().page;
componentDidShow() {
const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx);
tabbar?.setSelected(2);
}
// 以上是TabBar相关
render(): ReactNode {
return (
<View>
<Text>Member Page</Text>
</View>
);
}
}
+71 -22
View File
@@ -17,6 +17,8 @@ import type CustomTabBar from '@/custom-tab-bar';
import repairLogo from '@/assets/icons/RepairPage/repair.svg'; import repairLogo from '@/assets/icons/RepairPage/repair.svg';
import DetailFramework from '@/components/DetailFramework/DetailFramework'; import DetailFramework from '@/components/DetailFramework/DetailFramework';
import { getCurrentTicket } from '@/service/currentTicket'; import { getCurrentTicket } from '@/service/currentTicket';
import { randomInt } from '@/utils/random';
import wechatUser from '@/wechat';
import './repair.scss'; import './repair.scss';
interface RepairPageState { interface RepairPageState {
@@ -29,7 +31,7 @@ interface RepairPageState {
isLoading: boolean; isLoading: boolean;
isDisable: boolean; isDisable: boolean;
checkedList: Array<number>; checkedList: Array<number>;
currentTicketsId: Array<number>; currentTicketsIdName: Array<Map<number, string>>;
} }
const submitInterval = 5000; const submitInterval = 5000;
@@ -37,7 +39,7 @@ const submitInterval = 5000;
const middleButton = <View></View>; const middleButton = <View></View>;
const isInfoShow = { const isInfoShow = {
device: true, device: false,
createdTime: true, createdTime: true,
description: false, description: false,
current: true, current: true,
@@ -50,17 +52,17 @@ export default class RepairPage extends Component<{}, RepairPageState> {
type: 1 as 0 | 1, type: 1 as 0 | 1,
device: '', device: '',
deviceModel: '', deviceModel: '',
owner: '', owner: wechatUser.getInfo().name,
phone: '', phone: wechatUser.getInfo().phone,
description: '', description: '',
isLoading: false, isLoading: false,
isDisable: true, isDisable: true,
checkedList: [0], checkedList: [0],
currentTicketsId: [] as Array<number>, currentTicketsIdName: [] as Array<Map<number, string>>,
}; };
componentDidMount(): void { componentDidMount(): void {
getCurrentTicket(this, middleButton, isInfoShow); getCurrentTicket(this);
setTimeout(() => { setTimeout(() => {
this.setState({ this.setState({
@@ -152,30 +154,77 @@ export default class RepairPage extends Component<{}, RepairPageState> {
onSubmit() { onSubmit() {
this.setState({ this.setState({
isLoading: true,
isDisable: true, isDisable: true,
}); });
if (
this.state.description == '' ||
this.state.device == '' ||
this.state.deviceModel == '' ||
this.state.owner == '' ||
this.state.phone == '' ||
this.state.checkedList.length === 0
) {
Taro.atMessage({
message: pt.get().button.submitText.blank,
type: 'error',
});
setTimeout(() => {
this.setState({
isDisable: false,
});
}, submitInterval);
return;
}
submitTicket(this); submitTicket(this);
Taro.reLaunch({ setTimeout(() => {
url: '/pages/repair/repair', this.setState({
}); isDisable: false,
});
}, submitInterval);
} }
render(): ReactNode { render(): ReactNode {
const ticketsRenderer = this.state.currentTicketsId.map((id, idx) => ( const ticketsRenderer =
<AtCard key={idx}> this.state.currentTicketsIdName.length !== 0 ? (
<DetailFramework this.state.currentTicketsIdName.map((pair, idx) => (
id={id} <AtCard
isInfoShow={isInfoShow} key={idx}
middleButton={middleButton} title={pair.values().next().value} //pair.keys().next().value == ticket['device'] + ' ' + ticket['deviceModel']
/> extra={pt.get().repairPage.currentTicket.extra}
</AtCard> onClick={() => {
)); Taro.navigateTo({
console.log(ticketsRenderer); url:
'/pages/TicketDetail/TicketDetail?id=' +
pair.keys().next().value,
});
}}
note={
pt.get().tips.tipsText[
randomInt(0, pt.get().tips.tipsText.length - 1)
]
}
>
<DetailFramework
id={pair.keys().next().value} //pair.keys().next().value == id
isInfoShow={isInfoShow}
middleButton={middleButton}
/>
</AtCard>
))
) : (
<View></View>
);
return ( return (
<View> <View style={{ width: '94%', marginLeft: '3%' }}>
<AtMessage /> <AtMessage />
{ticketsRenderer} <View
style={{
marginTop: '20rpx',
marginBottom: '40rpx',
}}
>
{ticketsRenderer}
</View>
<AtCard <AtCard
note={pt.get().repairPage.cardText.note} note={pt.get().repairPage.cardText.note}
title={pt.get().repairPage.cardText.title} title={pt.get().repairPage.cardText.title}
+57 -2
View File
@@ -1,5 +1,5 @@
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import { View } from '@tarojs/components'; import { Image, View } from '@tarojs/components';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt from '@/plain-text'; import pt from '@/plain-text';
import './about.scss'; import './about.scss';
@@ -11,6 +11,61 @@ export default class AboutPage extends Component {
}); });
} }
render(): ReactNode { render(): ReactNode {
return <View></View>; return (
<View>
<View
style={{ marginTop: '60rpx', marginBottom: '60rpx' }}
className='at-row at-row__align--start'
>
<View className='at-col at-col-1 at-col--auto'>
<Image
style='width: 240rpx; height: 240rpx; margin-left: 60rpx; margin-right: 30rpx; margin-top: 30rpx; border-radius: 120rpx'
src='https://wiki.zjueva.net/images/1/10/%E5%A4%B4%E5%83%8F.jpg?20240319171222'
mode='aspectFit'
/>
</View>
<View className='at-article at-col'>
<View className='at-article__h1'>
{pt.get().aboutPage.dean.nickname}
</View>
<View className='at-article__h3'>
{pt.get().aboutPage.dean.username}
</View>
<View className='at-article__p'>
{pt.get().aboutPage.dean.status}
</View>
<View className='at-article__info'>
{pt.get().aboutPage.dean.note}
</View>
</View>
</View>
<View
style={{ marginTop: '60rpx', marginBottom: '60rpx' }}
className='at-row at-row__align--start'
>
<View className='at-col at-col-1 at-col--auto'>
<Image
style='width: 240rpx; height: 240rpx; margin-left: 60rpx; margin-right: 30rpx; margin-top: 30rpx; border-radius: 120rpx'
src='https://wiki.zjueva.net/images/1/10/%E5%A4%B4%E5%83%8F.jpg?20240319171222'
mode='aspectFit'
/>
</View>
<View className='at-article at-col'>
<View className='at-article__h1'>
{pt.get().aboutPage.fracher.nickname}
</View>
<View className='at-article__h3'>
{pt.get().aboutPage.fracher.username}
</View>
<View className='at-article__p'>
{pt.get().aboutPage.fracher.status}
</View>
<View className='at-article__info'>
{pt.get().aboutPage.fracher.note}
</View>
</View>
</View>
</View>
);
} }
} }
+26 -13
View File
@@ -4,14 +4,15 @@ import { View } from '@tarojs/components';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt from '@/plain-text'; import pt from '@/plain-text';
import { updateUserInfo } from '@/service/userData'; import { updateUserInfo } from '@/service/userData';
import wechatUser from '@/wechat';
import './inform.scss'; import './inform.scss';
const submitInterval = 5000; const submitInterval = 5000;
export default class InformPage extends Component { export default class InformPage extends Component {
state = { state = {
phone: '', phone: wechatUser.getInfo().phone,
name: '', name: wechatUser.getInfo().name,
isLoading: false, isLoading: false,
isDisable: false, isDisable: false,
}; };
@@ -36,10 +37,20 @@ export default class InformPage extends Component {
} }
onSubmit() { onSubmit() {
this.setState({ this.setState({
isLoading: true,
isDisable: true, isDisable: true,
}); });
console.log(this.state.name, this.state.phone); if (this.state.name == '' || this.state.phone == '') {
Taro.atMessage({
message: pt.get().button.submitText.blank,
type: 'error',
});
setTimeout(() => {
this.setState({
isDisable: false,
});
}, submitInterval);
return;
}
updateUserInfo(this); updateUserInfo(this);
setTimeout(() => { setTimeout(() => {
this.setState({ this.setState({
@@ -50,7 +61,7 @@ export default class InformPage extends Component {
render(): ReactNode { render(): ReactNode {
return ( return (
<View> <View style={{ marginTop: '30rpx', width: '94%', marginLeft: '3%' }}>
<AtForm onSubmit={this.onSubmit.bind(this)}> <AtForm onSubmit={this.onSubmit.bind(this)}>
<AtMessage /> <AtMessage />
<AtInput <AtInput
@@ -73,14 +84,16 @@ export default class InformPage extends Component {
value={this.state.name} value={this.state.name}
onChange={this.handleChangeName.bind(this)} onChange={this.handleChangeName.bind(this)}
/> />
<AtButton <View style={{ marginTop: '30rpx' }}>
loading={this.state.isLoading} <AtButton
formType='submit' loading={this.state.isLoading}
type='primary' formType='submit'
disabled={this.state.isDisable} type='primary'
> disabled={this.state.isDisable}
{pt.get().button.buttonText.submit} >
</AtButton> {pt.get().button.buttonText.submit}
</AtButton>
</View>
</AtForm> </AtForm>
</View> </View>
); );
+70 -63
View File
@@ -1,13 +1,15 @@
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import { AtForm, AtInput, AtButton, AtMessage } from 'taro-ui'; import { AtForm, AtInput, AtButton, AtMessage } from 'taro-ui';
import { getUrl } from '@/service';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt from '@/plain-text'; import pt from '@/plain-text';
import { memberLogin, memberLogout } from '@/service/memberLogin';
import wechatUser from '@/wechat';
import { View } from '@tarojs/components';
import './member.scss'; import './member.scss';
const loginInterval = 5000; const logInterval = 5000;
export default class MemberPage extends Component { export default class UserMemberPage extends Component {
state = { state = {
stuid: '', stuid: '',
passwd: '', passwd: '',
@@ -16,7 +18,7 @@ export default class MemberPage extends Component {
}; };
componentDidMount(): void { componentDidMount(): void {
Taro.setNavigationBarTitle({ Taro.setNavigationBarTitle({
title: pt.get().navBar.user.member, title: pt.get().navBar.user.memberLogin,
}); });
} }
handleChangeStuid(stuid: string) { handleChangeStuid(stuid: string) {
@@ -33,76 +35,81 @@ export default class MemberPage extends Component {
} }
onSubmit() { onSubmit() {
this.setState({ this.setState({
isLoading: true,
isDisable: true, isDisable: true,
}); });
console.log([this.state.stuid, this.state.passwd]); if (this.state.stuid == '' || this.state.passwd == '') {
Taro.request({ Taro.atMessage({
url: getUrl('/member/login'), message: pt.get().button.submitText.blank,
method: 'POST', type: 'error',
data: {
token: 'token_test',
name: this.state.stuid,
passwd: this.state.passwd,
},
})
.then((res) => {
console.log(res.data);
Taro.atMessage({
message: pt.get().button.loginText.success,
type: 'success',
});
})
.catch((err) => {
console.log(err);
Taro.atMessage({
message: pt.get().button.loginText.error + err.toString(),
type: 'error',
});
}); });
this.setState({ setTimeout(() => {
isLoading: false, this.setState({
}); isDisable: false,
});
}, logInterval);
return;
}
memberLogin(this);
setTimeout(() => { setTimeout(() => {
this.setState({ this.setState({
isDisable: false, isDisable: false,
}); });
}, loginInterval); }, logInterval);
}
onLogout() {
this.setState({
isDisable: true,
});
memberLogout(this);
setTimeout(() => {
this.setState({
isDisable: false,
});
}, logInterval);
} }
render(): ReactNode { render(): ReactNode {
return ( return !wechatUser.getAccess() ? (
<AtForm onSubmit={this.onSubmit.bind(this)}> <View style={{ marginTop: '30rpx', width: '94%', marginLeft: '3%' }}>
<AtMessage /> <AtForm onSubmit={this.onSubmit.bind(this)}>
<AtInput <AtMessage />
required <AtInput
name='stuid' required
title={pt.get().memberPage.stuidText.title} name='stuid'
type='number' title={pt.get().memberPage.stuidText.title}
clear type='number'
placeholder={pt.get().memberPage.stuidText.placeholder} clear
value={this.state.stuid} placeholder={pt.get().memberPage.stuidText.placeholder}
onChange={this.handleChangeStuid.bind(this)} value={this.state.stuid}
/> onChange={this.handleChangeStuid.bind(this)}
<AtInput />
clear <AtInput
required clear
name='name' required
title={pt.get().memberPage.passwdText.title} name='name'
type='password' title={pt.get().memberPage.passwdText.title}
placeholder={pt.get().memberPage.passwdText.placeholder} type='password'
value={this.state.passwd} placeholder={pt.get().memberPage.passwdText.placeholder}
onChange={this.handleChangePasswd.bind(this)} value={this.state.passwd}
/> onChange={this.handleChangePasswd.bind(this)}
<AtButton />
loading={this.state.isLoading} <AtButton
formType='submit' loading={this.state.isLoading}
type='primary' formType='submit'
disabled={this.state.isDisable} type='primary'
> disabled={this.state.isDisable}
{pt.get().button.buttonText.login} >
{pt.get().button.buttonText.login}
</AtButton>
</AtForm>
</View>
) : (
<View style={{ marginTop: '30rpx', width: '94%', marginLeft: '3%' }}>
<AtButton type='primary' onClick={this.onLogout.bind(this)}>
{pt.get().button.buttonText.logout}
</AtButton> </AtButton>
</AtForm> </View>
); );
} }
} }
+60 -49
View File
@@ -1,8 +1,9 @@
import { AtTextarea, AtButton, AtForm, AtMessage } from 'taro-ui'; import { AtTextarea, AtButton, AtForm, AtMessage } from 'taro-ui';
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import { getUrl } from '@/service';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt from '@/plain-text'; import pt from '@/plain-text';
import { reportMessage } from '@/service/report';
import { View } from '@tarojs/components';
import './report.scss'; import './report.scss';
const submitInterval = 5000; const submitInterval = 5000;
@@ -27,35 +28,21 @@ export default class ReportPage extends Component {
} }
onSubmit() { onSubmit() {
this.setState({ this.setState({
isLoading: true,
isDisable: true, isDisable: true,
}); });
console.log(this.state.report); if (this.state.report == '') {
Taro.request({ Taro.atMessage({
url: getUrl('/report'), message: pt.get().button.submitText.blank,
method: 'POST', type: 'error',
data: {
token: 'token_test',
report: this.state.report,
},
})
.then((res) => {
console.log(res.data);
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
})
.catch((err) => {
console.log(err);
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
}); });
this.setState({ setTimeout(() => {
isLoading: false, this.setState({
}); isDisable: false,
});
}, submitInterval);
return;
}
reportMessage(this);
setTimeout(() => { setTimeout(() => {
this.setState({ this.setState({
isDisable: false, isDisable: false,
@@ -69,29 +56,53 @@ export default class ReportPage extends Component {
} }
render(): ReactNode { render(): ReactNode {
return ( return (
<AtForm <View style={{ marginTop: '30rpx', width: '94%', marginLeft: '3%' }}>
onSubmit={this.onSubmit.bind(this)} <AtForm
onReset={this.onReset.bind(this)} onSubmit={this.onSubmit.bind(this)}
> onReset={this.onReset.bind(this)}
<AtMessage />
<AtTextarea
value={this.state.report}
onChange={this.handleChange.bind(this)}
maxLength={200}
placeholder={pt.get().reportPage.placeHolderText}
/>
<AtButton
loading={this.state.isLoading}
formType='submit'
type='primary'
disabled={this.state.isDisable}
> >
{pt.get().button.buttonText.submit} <AtMessage />
</AtButton> <AtTextarea
<AtButton formType='reset' type='secondary'> value={this.state.report}
{pt.get().button.buttonText.reset} onChange={this.handleChange.bind(this)}
</AtButton> maxLength={200}
</AtForm> placeholder={pt.get().reportPage.placeHolderText}
/>
<View className='at-row'>
<View
className='at-col'
style={{
marginTop: '30rpx',
marginRight: '10rpx',
marginLeft: '10rpx',
width: '50%',
}}
>
<AtButton formType='reset' type='secondary'>
{pt.get().button.buttonText.reset}
</AtButton>
</View>
<View
className='at-col'
style={{
marginTop: '30rpx',
marginRight: '10rpx',
marginLeft: '10rpx',
width: '50%',
}}
>
<AtButton
loading={this.state.isLoading}
formType='submit'
type='primary'
disabled={this.state.isDisable}
>
{pt.get().button.buttonText.submit}
</AtButton>
</View>
</View>
</AtForm>
</View>
); );
} }
} }
+25 -19
View File
@@ -4,14 +4,16 @@ import { View, Picker, Image, Text } from '@tarojs/components';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import type CustomTabBar from '@/custom-tab-bar'; import type CustomTabBar from '@/custom-tab-bar';
import PageFooter from '@/components/PageFooter/PageFooter'; import PageFooter from '@/components/PageFooter/PageFooter';
import aboutIcon from '@/assets/icons/AboutPage/about.svg'; import aboutIcon from '@/assets/icons/UserPage/about.svg';
import userIcon from '@/assets/icons/UserPage/user.svg';
import clockIcon from '@/assets/icons/UserPage/clock.svg';
import messageIcon from '@/assets/icons/UserPage/message.svg';
import pt, { Lang } from '@/plain-text'; import pt, { Lang } from '@/plain-text';
import wechatUser from '@/wechat';
import logo from '@/assets/images/UserPage/logo.png'; import logo from '@/assets/images/UserPage/logo.png';
import { setLocaleData } from '@/service/localeData'; import { setLocaleData } from '@/service/localeData';
import wechatUser from '@/wechat';
import './user.scss'; import './user.scss';
const listLangInterval = 20;
const memberClickTimes = 7; const memberClickTimes = 7;
export default class UserPage extends Component { export default class UserPage extends Component {
@@ -24,14 +26,13 @@ export default class UserPage extends Component {
clicks: memberClickTimes, clicks: memberClickTimes,
isToastOpen: false, isToastOpen: false,
toastText: '', toastText: '',
haveAccess: wechatUser.getAccess(),
}; };
// 以下是TabBar相关 // 以下是TabBar相关
pageCtx = Taro.getCurrentInstance().page; pageCtx = Taro.getCurrentInstance().page;
componentDidShow() { componentDidShow() {
const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx); const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx);
tabbar?.setSelected(this.state.haveAccess ? 3 : 2); tabbar?.setSelected(2);
} }
// 以上是TabBar相关 // 以上是TabBar相关
@@ -105,11 +106,11 @@ export default class UserPage extends Component {
<View> <View>
<View <View
className='at-row at-row__justify--center at-row__align--end' className='at-row at-row__justify--center at-row__align--end'
style='height:110px;' style='height:220rpx;'
> >
<Image <Image
onTap={this.onTapImage} onTap={this.onTapImage}
style='width: 100px;height: 100px;' style='width: 200rpx;height: 200rpx;'
src={logo} src={logo}
mode='aspectFit' mode='aspectFit'
/> />
@@ -120,31 +121,36 @@ export default class UserPage extends Component {
></AtToast> ></AtToast>
<View <View
className='at-row at-row__justify--center at-row__align--center' className='at-row at-row__justify--center at-row__align--center'
style='height:60px;color:#696969;' style='height:120rpx;color:#696969;'
> >
<Text> EVA Notify v1.0.0</Text> <Text style={{ fontSize: '32rpx' }}> EVA Notify v1.0.0</Text>
</View> </View>
<AtList> <AtList>
<AtListItem <AtListItem
title={pt.get().userPage.ticketColumn.title} title={pt.get().userPage.ticketColumn.title}
note={pt.get().userPage.ticketColumn.note} note={pt.get().userPage.ticketColumn.note}
arrow='right' arrow='right'
iconInfo={{ color: '#E69966', value: 'clock' }} thumb={clockIcon}
onClick={this.myTicketPage} onClick={this.myTicketPage}
/> />
<AtListItem {wechatUser.getAccess() ? (
title={pt.get().userPage.infoColumn.title} <View></View>
note={pt.get().userPage.infoColumn.note} ) : (
arrow='right' <AtListItem
iconInfo={{ color: '#78A4FA', value: 'user' }} title={pt.get().userPage.infoColumn.title}
onClick={this.informPage} note={pt.get().userPage.infoColumn.note}
/> arrow='right'
thumb={userIcon}
onClick={this.informPage}
/>
)}
<AtListItem <AtListItem
title={pt.get().userPage.reportColumn.title} title={pt.get().userPage.reportColumn.title}
note={pt.get().userPage.reportColumn.note} note={pt.get().userPage.reportColumn.note}
extraText='' extraText=''
arrow='right' arrow='right'
iconInfo={{ color: '#9ACD32', value: 'message' }} thumb={messageIcon}
onClick={this.reportPage} onClick={this.reportPage}
/> />
<AtListItem <AtListItem
@@ -155,7 +161,7 @@ export default class UserPage extends Component {
thumb={aboutIcon} thumb={aboutIcon}
onClick={this.aboutPage} onClick={this.aboutPage}
/> />
<View style={{ height: listLangInterval }}></View> <View style={{ height: '40rpx' }}></View>
<Picker <Picker
mode='selector' mode='selector'
range={this.state.selector} range={this.state.selector}
+42 -3
View File
@@ -1,5 +1,44 @@
export interface AboutPageText {} export interface AboutPageText {
dean: {
nickname: string;
username: string;
status: string;
note: string;
};
fracher: {
nickname: string;
username: string;
status: string;
note: string;
};
}
export const aboutPageZhCn: AboutPageText = {}; export const aboutPageZhCn: AboutPageText = {
dean: {
nickname: '晓洋',
username: '@ Dawn_Ocean',
status: 'Eta & Tea 总设计',
note: '摸鱼与开发叠加态',
},
fracher: {
nickname: '宇航员',
username: '@ FrozenArcher',
status: 'Ate 总设计, Eta 合作贡献者',
note: '6~',
},
};
export const aboutPageEnUs: AboutPageText = {}; export const aboutPageEnUs: AboutPageText = {
dean: {
nickname: 'Dean Ma',
username: '@ Dawn_Ocean',
status: "Eta & Tea's General Designer",
note: 'Struggling between developing & laziness',
},
fracher: {
nickname: 'Fracher',
username: '@ FrozenArcher',
status: "Ate's General Designer, Eta's Contributor",
note: '6~',
},
};
+21
View File
@@ -3,14 +3,21 @@ export interface ButtonText {
submit: string; submit: string;
reset: string; reset: string;
login: string; login: string;
logout: string;
}; };
submitText: { submitText: {
success: string; success: string;
error: string; error: string;
blank: string;
}; };
loginText: { loginText: {
success: string; success: string;
error: string; error: string;
fail: string;
};
logoutText: {
success: string;
error: string;
}; };
} }
@@ -19,14 +26,21 @@ export const buttonZhCn: ButtonText = {
submit: '提交', submit: '提交',
reset: '清空', reset: '清空',
login: '登录', login: '登录',
logout: '登出',
}, },
submitText: { submitText: {
success: '提交成功', success: '提交成功',
error: '提交失败:', error: '提交失败:',
blank: '请填写完整!',
}, },
loginText: { loginText: {
success: '登录成功', success: '登录成功',
error: '登录失败', error: '登录失败',
fail: '请检查用户名或密码!',
},
logoutText: {
success: '登出成功',
error: '登出失败',
}, },
}; };
@@ -35,13 +49,20 @@ export const buttonEnUs: ButtonText = {
submit: 'Submit', submit: 'Submit',
reset: 'Reset', reset: 'Reset',
login: 'Login', login: 'Login',
logout: 'Logout',
}, },
submitText: { submitText: {
success: 'Success', success: 'Success',
error: 'Error: ', error: 'Error: ',
blank: 'Please fill in the blanks!',
}, },
loginText: { loginText: {
success: 'Login Success', success: 'Login Success',
error: 'Login Failed', error: 'Login Failed',
fail: 'Please check username or password!',
},
logoutText: {
success: 'Logout Success',
error: 'Logout Failed',
}, },
}; };
+7 -3
View File
@@ -31,7 +31,7 @@ export interface MainPageText {
}; };
inDuty: { inDuty: {
title: string; title: string;
currentDutyText: (c: 'off' | '1' | '2' | '3') => string; currentDutyText: (c: 'off' | '1' | '2' | '3' | 'others') => string;
inDutyCnt: (n: number) => string; inDutyCnt: (n: number) => string;
}; };
}; };
@@ -41,7 +41,7 @@ export const mainPageZhCn: MainPageText = {
mainTitleLine: '您好,这里是E志者协会', mainTitleLine: '您好,这里是E志者协会',
subTitleLine: '维修请至【东三-204】实验室', subTitleLine: '维修请至【东三-204】实验室',
cardTitle: { cardTitle: {
dutyInfo: '204 值班情况', dutyInfo: '值班情况',
stepInfo: '维修步骤', stepInfo: '维修步骤',
tipsInfo: '注意事项', tipsInfo: '注意事项',
}, },
@@ -66,7 +66,7 @@ export const mainPageZhCn: MainPageText = {
{ title: '维修结束,取回电脑' }, { title: '维修结束,取回电脑' },
], ],
tipsList: [ tipsList: [
{ title: '戴尔/外星人、Surface、苹果电脑不能拆机哦~' }, { title: '戴尔/外星人、Surface、苹果电脑不能拆哦~' },
{ title: '数据无价,请随时做好数据备份哦~' }, { title: '数据无价,请随时做好数据备份哦~' },
{ title: '204 也是实验室,请勿在内饮食~' }, { title: '204 也是实验室,请勿在内饮食~' },
{ title: '我们是志愿服务,不收取任何礼物哦~' }, { title: '我们是志愿服务,不收取任何礼物哦~' },
@@ -89,6 +89,8 @@ export const mainPageZhCn: MainPageText = {
return '第二班 16:00-18:00'; return '第二班 16:00-18:00';
case '3': case '3':
return '第三班 18:00-20:30'; return '第三班 18:00-20:30';
case 'others':
return '其他值班时间,见通知';
} }
}, },
inDutyCnt: (n) => '当前值班人数:' + n, inDutyCnt: (n) => '当前值班人数:' + n,
@@ -148,6 +150,8 @@ export const mainPageEnUs: MainPageText = {
return '2nd Shift 16:00-18:00'; return '2nd Shift 16:00-18:00';
case '3': case '3':
return '3rd Shift 18:00-20:30'; return '3rd Shift 18:00-20:30';
case 'others':
return 'Other duty time, see notice';
} }
}, },
inDutyCnt: (n) => 'EVA members on duty: ' + n, inDutyCnt: (n) => 'EVA members on duty: ' + n,
+178
View File
@@ -1,4 +1,15 @@
export interface MemberPageText { export interface MemberPageText {
mainTitleLine: string;
subTitleLine: string;
cardTitle: {
dutyInfo: string;
stepInfo: string;
tipsInfo: string;
};
dutyCount: {
button: string;
text: string;
};
stuidText: { stuidText: {
title: string; title: string;
placeholder: string; placeholder: string;
@@ -7,9 +18,52 @@ export interface MemberPageText {
title: string; title: string;
placeholder: string; placeholder: string;
}; };
uncompletedTicket: {
extra: string;
};
dutyCard: {
offDuty: {
title: string;
reason: (s: string) => string;
recoverTime: (t: string) => string;
};
inDuty: {
title: string;
currentDutyText: (c: 'off' | '1' | '2' | '3' | 'others') => string;
inDutyCnt: (n: number) => string;
};
};
expandTitle: {
stepInfo: string;
tipsInfo: string;
admin: string;
};
cardTips: {
dutyInfo: string;
stepInfo: string;
tipsInfo: string;
};
extraInfo: {
dutyInfo: string;
stepInfo: string;
tipsInfo: string;
};
stepList: Array<{ title: string }>;
tipsList: Array<{ title: string }>;
} }
export const memberPageZhCn: MemberPageText = { export const memberPageZhCn: MemberPageText = {
mainTitleLine: '您好,',
subTitleLine: '祝你满绩每一天',
cardTitle: {
dutyInfo: '值班情况',
stepInfo: '维修步骤',
tipsInfo: '注意事项',
},
dutyCount: {
button: '更新值班人数',
text: '当前值班人数:',
},
stuidText: { stuidText: {
title: '学号', title: '学号',
placeholder: '与统一身份认证学号一致', placeholder: '与统一身份认证学号一致',
@@ -18,9 +72,75 @@ export const memberPageZhCn: MemberPageText = {
title: '密码', title: '密码',
placeholder: '与 EVA 统一身份认证一致', placeholder: '与 EVA 统一身份认证一致',
}, },
uncompletedTicket: {
extra: '详细信息',
},
dutyCard: {
offDuty: {
title: '空闲',
reason: (s) => '未值班原因:' + s,
recoverTime: (t) => '恢复值班时间:' + t,
},
inDuty: {
title: '值班中',
currentDutyText: (c) => {
switch (c) {
case 'off':
return '当前未值班';
case '1':
return '第一班 13:30-16:00';
case '2':
return '第二班 16:00-18:00';
case '3':
return '第三班 18:00-20:30';
case 'others':
return '其他值班时间,见通知';
}
},
inDutyCnt: (n) => '当前值班人数:' + n,
},
},
expandTitle: {
stepInfo: '查看维修步骤',
tipsInfo: '查看注意事项',
admin: '组长管理入口',
},
cardTips: {
dutyInfo: '提示:可以先前往【维修】页面在线上预填写工单!',
stepInfo: '提示:请在 20:30 之前取走自己的物品哦!',
tipsInfo: '',
},
extraInfo: {
dutyInfo: '',
stepInfo: '',
tipsInfo: '',
},
stepList: [
{ title: '机主线上填写工单,审核接取维修后加入 Oreo' },
{ title: '进行维修工作,认领工单,通过小程序与机主交流' },
{ title: '维修结束,清点机主物品,待机主取回' },
{ title: '机主取回机器确认无误后,修改工单状态' },
],
tipsList: [
{ title: '戴尔/外星人、Surface、苹果电脑不能拆机' },
{ title: '数据无价,请提醒机主随时做好数据备份' },
{ title: '离开 204 前清点好维修物资!' },
{ title: '螺丝上了吗?电源排线插了吗?' },
],
}; };
export const memberPageEnUs: MemberPageText = { export const memberPageEnUs: MemberPageText = {
mainTitleLine: 'Hi! ',
subTitleLine: 'Have a great day!',
cardTitle: {
dutyInfo: 'Duty Situation',
stepInfo: 'Maintenance Steps',
tipsInfo: 'Tips',
},
dutyCount: {
button: 'Update Duty Count',
text: 'The duty count: ',
},
stuidText: { stuidText: {
title: 'Student ID', title: 'Student ID',
placeholder: 'Consistent with EVA Auth', placeholder: 'Consistent with EVA Auth',
@@ -29,4 +149,62 @@ export const memberPageEnUs: MemberPageText = {
title: 'Password', title: 'Password',
placeholder: 'Consistent with EVA Auth', placeholder: 'Consistent with EVA Auth',
}, },
uncompletedTicket: {
extra: 'Details',
},
dutyCard: {
offDuty: {
title: 'Off Duty',
reason: (s) => 'Off duty reason: ' + s,
recoverTime: (t) => 'Resumption of duty: ' + t,
},
inDuty: {
title: 'On Duty',
currentDutyText: (c) => {
switch (c) {
case 'off':
return 'Currently not on duty';
case '1':
return '1st Shift 13:30-16:00';
case '2':
return '2nd Shift 16:00-18:00';
case '3':
return '3rd Shift 18:00-20:30';
case 'others':
return 'Other duty hours, see notice';
}
},
inDutyCnt: (n) => 'EVA members on duty: ' + n,
},
},
expandTitle: {
stepInfo: 'Check for maintenance steps',
tipsInfo: 'Check for tips',
admin: 'Entry for admin',
},
cardTips: {
dutyInfo: '提示:可以先前往【维修】页面在线上预填写工单!',
stepInfo: '提示:请在 20:30 之前取走自己的物品哦!',
tipsInfo: '',
},
extraInfo: {
dutyInfo: '',
stepInfo: '',
tipsInfo: '',
},
stepList: [
{ title: 'The owner fills out ticket online. Add it to Oreo after audit.' },
{ title: 'Repair, pick the ticket, and communicate with the owner online' },
{
title:
"Maintenance completed, inventory owner's belongings and await retrieving",
},
{ title: 'Modify the work order status after the owner retrieves.' },
],
tipsList: [
{ title: 'Dell/Alienware, Surface, Apple cannot be dissassembled.' },
{ title: 'Please remind the owner to backup data at any time!' },
{ title: '204 is a laboratory. Do not eat inside.' },
{ title: 'Are the screws on? Is the power cable plugged in?' },
],
}; };
+52
View File
@@ -0,0 +1,52 @@
export interface ModalText {
pick: {
title: string;
content: string;
};
addToOreo: {
title: string;
content: string;
};
retrieve: {
title: string;
content: string;
};
cancel: string;
confirm: string;
}
export const modalZhCn: ModalText = {
pick: {
title: '认领此工单',
content: '工单可多人认领!认领后将无法撤销!',
},
addToOreo: {
title: '将工单加入 Oreo',
content: '确认加入 Oreo?加入后将无法撤回!',
},
retrieve: {
title: '机器取回确认',
content: '确认该机器已取回?取回后工单完成,将无法添加评论!',
},
cancel: '取消',
confirm: '确认',
};
export const modalEnUs: ModalText = {
pick: {
title: 'Pick this ticket',
content:
'Tickets can be claimed by multiple members! Once claimed, it will not be able to be revoked!',
},
addToOreo: {
title: 'Add ticket to Oreo',
content: 'Once Confirmed, the change will be irrevocably!',
},
retrieve: {
title: 'Confirm the retrieving',
content:
'Once Confirmed, the ticket will be closed and cannot add any comment!',
},
cancel: 'Cancel',
confirm: 'Confirm',
};
+6 -3
View File
@@ -3,9 +3,10 @@ export interface NavBarTitle {
user: { user: {
myTicket: string; myTicket: string;
report: string; report: string;
member: string; memberLogin: string;
inform: string; inform: string;
about: string; about: string;
member: string;
}; };
} }
@@ -16,7 +17,8 @@ export const navBarTitleZhCn: NavBarTitle = {
report: '意见反馈', report: '意见反馈',
inform: '我的信息', inform: '我的信息',
about: '关于我们', about: '关于我们',
member: '协会成员登录', memberLogin: '协会成员登录',
member: '协会成员',
}, },
}; };
@@ -27,6 +29,7 @@ export const navBarTitleEnUs: NavBarTitle = {
report: 'Report', report: 'Report',
inform: 'Information', inform: 'Information',
about: 'About us', about: 'About us',
member: 'Member login', memberLogin: 'Member login',
member: 'Member Page',
}, },
}; };
+4 -4
View File
@@ -50,7 +50,7 @@ export const repairPageZhCn: RepairPageText = {
errorMessage: '未获取到工单!', errorMessage: '未获取到工单!',
title: '', title: '',
note: '', note: '',
extra: '', extra: '详细信息',
}, },
typeText: { typeText: {
computer: '电脑', computer: '电脑',
@@ -74,7 +74,7 @@ export const repairPageZhCn: RepairPageText = {
}, },
descriptionText: { descriptionText: {
title: '问题描述', title: '问题描述',
placeholder: '如:ZJUWLAN 无法登入校内网站', placeholder: '如:无法登入校内网站',
}, },
checkboxText: { checkboxText: {
none: '无附件', none: '无附件',
@@ -94,10 +94,10 @@ export const repairPageZhCn: RepairPageText = {
export const repairPageEnUs: RepairPageText = { export const repairPageEnUs: RepairPageText = {
currentTicket: { currentTicket: {
errorMessage: '未获取到工单!', errorMessage: 'Cannot get the ticket!',
title: '', title: '',
note: '', note: '',
extra: '', extra: 'Details',
}, },
typeText: { typeText: {
computer: 'Computer', computer: 'Computer',
+90 -11
View File
@@ -2,7 +2,7 @@ interface StepItem {
title: string; title: string;
} }
type StatusStr = '1' | '2' | '3' | '4' | '5'; type StatusStr = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7';
export interface TicketDetailText { export interface TicketDetailText {
stepItems: Array<StepItem>; stepItems: Array<StepItem>;
@@ -10,8 +10,32 @@ export interface TicketDetailText {
statusModifyPrefix: string; statusModifyPrefix: string;
statusModifyMessage: Map<StatusStr, string>; statusModifyMessage: Map<StatusStr, string>;
descTitle: string; descTitle: string;
divider: string;
info: {
title: string;
extra: string;
};
tookAway: string; tookAway: string;
addToOreo: string;
addNote: string; addNote: string;
pick: string;
comment: {
title: string;
placeholder: string;
};
status: {
button: string;
title: string;
cancel: string;
status0: string;
status1: string;
status2: string;
status3: string;
status4: string;
status5: string;
status6: string;
status7: string;
};
} }
export const ticketDetailZhCn: TicketDetailText = { export const ticketDetailZhCn: TicketDetailText = {
@@ -22,17 +46,44 @@ export const ticketDetailZhCn: TicketDetailText = {
{ title: '工单完成' }, { title: '工单完成' },
], ],
createTicketMessage: '创建了维修', createTicketMessage: '创建了维修',
statusModifyPrefix: '将维修状态更改为:', statusModifyPrefix: '将维修状态改为:',
statusModifyMessage: new Map<StatusStr, string>([ statusModifyMessage: new Map<StatusStr, string>([
['0', '已创建/交接中'],
['1', '维修中'], ['1', '维修中'],
['2', '2(?)'], ['2', '劝退待取回'],
['3', '3(?)'], ['3', '劝退已取回'],
['4', '维修成功待取回'], ['4', '维修成功待取回'],
['5', '维修成功已取回'], ['5', '维修成功已取回'],
['6', '维修翻车待取回'],
['7', '维修翻车已取回'],
]), ]),
descTitle: '问题描述', descTitle: '问题描述',
tookAway: '已取回', divider: '评论 / 状态',
info: {
title: '机主姓名',
extra: '联系方式',
},
tookAway: '我已取回',
addToOreo: '加入 Oreo',
addNote: '添加评论', addNote: '添加评论',
pick: '认领',
comment: {
title: '添加评论',
placeholder: '可以在这里交流机器情况、维修进度、提出问题~',
},
status: {
button: '改变工单状态',
title: '请选择要改变成为的状态',
cancel: '取消',
status0: '已创建/交接中',
status1: '维修中',
status2: '劝退待取回',
status3: '劝退已取回',
status4: '维修成功待取回',
status5: '维修成功已取回',
status6: '维修翻车待取回',
status7: '维修翻车已取回',
},
}; };
export const ticketDetailEnUs: TicketDetailText = { export const ticketDetailEnUs: TicketDetailText = {
@@ -45,13 +96,41 @@ export const ticketDetailEnUs: TicketDetailText = {
createTicketMessage: 'Created ticket', createTicketMessage: 'Created ticket',
statusModifyPrefix: 'Modified repair status to: ', statusModifyPrefix: 'Modified repair status to: ',
statusModifyMessage: new Map<StatusStr, string>([ statusModifyMessage: new Map<StatusStr, string>([
['0', 'Created / Handovering'],
['1', 'Repairing'], ['1', 'Repairing'],
['2', '2(?)'], ['2', 'Pending Retrieval (Refused)'],
['3', '3(?)'], ['3', 'Retrieved (Refused)'],
['4', 'Device to be retrieved'], ['4', 'Pending Retrieval (Finished)'],
['5', 'Ticket finished'], ['5', 'Retrieved (Finished)'],
['6', 'Pending Retrieval (Failed)'],
['7', 'Retrieved (Failed)'],
]), ]),
descTitle: 'Problem description', descTitle: 'Description',
divider: 'Comment / Status',
info: {
title: 'Name',
extra: 'Contact',
},
tookAway: 'Already retrieved', tookAway: 'Already retrieved',
addNote: 'Add a comment', addToOreo: 'Add to Oreo',
addNote: 'Comment',
pick: 'Pick',
comment: {
title: 'Add Comment',
placeholder:
'You can exchange information the device, the progress of repairs, and ask questions here.',
},
status: {
button: 'Modify Status',
title: 'Please select the status you want to modify to',
cancel: 'Cancel',
status0: 'Created / Handovering',
status1: 'Repairing',
status2: 'Pending Retrieval (Refused)',
status3: 'Retrieved (Refused)',
status4: 'Pending Retrieval (Finished)',
status5: 'Retrieved (Finished)',
status6: 'Pending Retrieval (Failed)',
status7: 'Retrieved (Failed)',
},
}; };
+17 -11
View File
@@ -1,4 +1,4 @@
type FixStatus = 1 | 2 | 3 | 4 | 5; import { FixStatus } from '@/common';
export interface TicketListText { export interface TicketListText {
createdAt(time: string): string; createdAt(time: string): string;
@@ -10,11 +10,14 @@ export const ticketListZhCn: TicketListText = {
return '创建于' + ' ' + time; return '创建于' + ' ' + time;
}, },
statusMap: new Map([ statusMap: new Map([
[1, '创建成功'], [0, '已创建/交接中'],
[2, '维修中'], [1, '维修中'],
[3, '待取回'], [2, '劝退待取回'],
[4, '已取回'], [3, '劝退已取回'],
[5, '已取回'], [4, '维修成功待取回'],
[5, '维修成功已取回'],
[6, '维修翻车待取回'],
[7, '维修翻车已取回'],
]), ]),
}; };
@@ -23,10 +26,13 @@ export const ticketListEnUs: TicketListText = {
return 'Created at' + ' ' + time; return 'Created at' + ' ' + time;
}, },
statusMap: new Map([ statusMap: new Map([
[1, 'Created'], [0, 'Created / Handovering'],
[2, 'Repairing'], [1, 'Repairing'],
[3, 'Pending Retrieval'], [2, 'Pending Retrieval (Refused)'],
[4, 'Retrieved'], [3, 'Retrieved (Refused)'],
[5, 'Retrieved'], [4, 'Pending Retrieval (Finished)'],
[5, 'Retrieved (Finished)'],
[6, 'Pending Retrieval (Failed)'],
[7, 'Retrieved (Failed)'],
]), ]),
}; };
+25
View File
@@ -0,0 +1,25 @@
export interface TipsText {
tipsText: Array<string>;
}
export const tipsZhCn: TipsText = {
tipsText: [
'提示:请在 20:30 之前取走自己的物品哦!',
'提示:戴尔/外星人、Surface、苹果电脑不能拆机哦~',
'提示:数据无价,请随时做好数据备份哦~',
'提示:204 也是实验室,请勿在内饮食~',
'提示:我们是志愿服务,不收取任何礼物哦~',
'提示:无论是有关于小程序的建议,还是关于E志者协会的建议,都可以在【意见反馈】处提出来哦!',
],
};
export const tipsEnUs: TipsText = {
tipsText: [
'Tips: Please retrieve your devices before 20:30!',
'Tips: Dell/Alienware, Surface, Apple cannot be dissassembled.',
'Tips: Data is priceless, please backup your data at any time!',
'Tips: 204 is also a laboratory. Do not eat inside.',
'Tips: We are volunteers and do not take any gifts.',
'Tips: Feel free to post your suggestions about the weapp or about us at [Account-Report]!',
],
};
+8
View File
@@ -16,6 +16,8 @@ import {
ticketDetailZhCn, ticketDetailZhCn,
} from './TicketDetail'; } from './TicketDetail';
import { CommonText, commonTextEnUs, commonTextZhCn } from './common'; import { CommonText, commonTextEnUs, commonTextZhCn } from './common';
import { TipsText, tipsEnUs, tipsZhCn } from './Tips';
import { ModalText, modalEnUs, modalZhCn } from './Modal';
interface TextRecord { interface TextRecord {
common: CommonText; common: CommonText;
@@ -32,6 +34,8 @@ interface TextRecord {
navBar: NavBarTitle; navBar: NavBarTitle;
repairPage: RepairPageText; repairPage: RepairPageText;
ticketDetail: TicketDetailText; ticketDetail: TicketDetailText;
tips: TipsText;
modal: ModalText;
} }
const textZhCn: TextRecord = { const textZhCn: TextRecord = {
@@ -49,6 +53,8 @@ const textZhCn: TextRecord = {
navBar: navBarTitleZhCn, navBar: navBarTitleZhCn,
repairPage: repairPageZhCn, repairPage: repairPageZhCn,
ticketDetail: ticketDetailZhCn, ticketDetail: ticketDetailZhCn,
tips: tipsZhCn,
modal: modalZhCn,
}; };
const textEnUs: TextRecord = { const textEnUs: TextRecord = {
@@ -66,6 +72,8 @@ const textEnUs: TextRecord = {
navBar: navBarTitleEnUs, navBar: navBarTitleEnUs,
repairPage: repairPageEnUs, repairPage: repairPageEnUs,
ticketDetail: ticketDetailEnUs, ticketDetail: ticketDetailEnUs,
tips: tipsEnUs,
modal: modalEnUs,
}; };
// type Lang = 'zh_CN' | 'en_US' | ...; // type Lang = 'zh_CN' | 'en_US' | ...;
+39
View File
@@ -0,0 +1,39 @@
import TicketDetail from '@/pages/TicketDetail/TicketDetail';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
export function addToOreo(that: TicketDetail) {
that.setState({
isOreoLoading: true,
});
Taro.request({
url: getUrl('/tickets/addtooreo'),
method: 'POST',
data: {
token: wechatUser.getToken(),
id: that.state.id,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isOreoLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
})
.catch((err) => {
console.log(err);
that.setState({
isOreoLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+46
View File
@@ -0,0 +1,46 @@
import MainPage from '@/pages/index';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
const reLaunchInterval = 1000;
export function changeDutyCnt(that: MainPage) {
that.setState({
isLoading: true,
});
Taro.request({
url: getUrl('/tickets/addtooreo'),
method: 'POST',
data: {
token: wechatUser.getToken(),
dutyCnt: that.state.inDutyCnt,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
setTimeout(() => {
Taro.reLaunch({
url: '/pages/index/index',
});
}, reLaunchInterval);
})
.catch((err) => {
console.log(err);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+47
View File
@@ -0,0 +1,47 @@
import TicketDetail from '@/pages/TicketDetail/TicketDetail';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
const reLaunchInterval = 1000;
export function changeStatus(that: TicketDetail, status: number) {
that.setState({
isStatusLoading: true,
});
Taro.request({
url: getUrl('/tickets/update'),
method: 'POST',
data: {
token: wechatUser.getToken(),
id: that.state.id,
status: status,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isStatusLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
setTimeout(() => {
Taro.reLaunch({
url: '/pages/TicketDetail/TicketDetail?id=' + that.state.id,
});
}, reLaunchInterval);
})
.catch((err) => {
console.log(err);
that.setState({
isStatusLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+41
View File
@@ -0,0 +1,41 @@
import Taro from '@tarojs/taro';
import { getUrl } from '.';
export function checkLogin(callback: (success: boolean) => void) {
let token = checkToken();
if (token.length !== 0) {
Taro.request({
url: getUrl('/checklogin'),
method: 'GET',
data: {
token: token,
},
})
.then((res) => {
if (res.data.data.islogin) {
callback(true);
}
callback(false);
})
.catch((err) => {
console.log(err);
callback(false);
});
} else {
callback(false);
}
}
export function checkToken(): string {
try {
let token: string = Taro.getStorageSync('token');
if (token) {
return token;
} else {
return '';
}
} catch (err) {
console.log(err);
return '';
}
}
+15 -7
View File
@@ -2,27 +2,35 @@ import RepairPage from '@/pages/repair/repair';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import { TicketListItem } from '@/components/TicketListItem/TicketListItem'; import { TicketListItem } from '@/components/TicketListItem/TicketListItem';
import pt from '@/plain-text'; import pt from '@/plain-text';
import DetailFramework from '@/components/DetailFramework/DetailFramework'; import wechatUser from '@/wechat';
import { getUrl } from '.'; import { getUrl } from '.';
export function getCurrentTicket(that: RepairPage, middleButton, isInfoShow) { export function getCurrentTicket(that: RepairPage) {
Taro.request({ Taro.request({
url: getUrl('/user/mytickets'), url: getUrl('/user/mytickets'),
method: 'GET', method: 'GET',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
}, },
}) })
.then((res) => { .then((res) => {
const data = res.data.data; const data = res.data.data;
let newIdList: Array<number> = []; let newIdNameList: Array<Map<number, string>> = [];
data.list.map((ticket: TicketListItem) => { data.list.map((ticket: TicketListItem) => {
if (ticket['status'] !== 5) { if (
newIdList.push(ticket.id); ticket['status'] !== 3 &&
ticket['status'] !== 5 &&
ticket['status'] !== 7
) {
newIdNameList.push(
new Map([
[ticket['id'], ticket['device'] + ' ' + ticket['deviceModel']],
]),
);
} }
}); });
that.setState({ that.setState({
currentTicketsId: newIdList, currentTicketsIdName: newIdNameList,
}); });
}) })
.catch((err) => { .catch((err) => {
+17 -2
View File
@@ -1,42 +1,57 @@
import MainPage from '@/pages/index'; import MainPage from '@/pages/index';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import wechatUser from '@/wechat';
import { getUrl } from '.'; import { getUrl } from '.';
export function getDutyInfo(that: MainPage) { export function getDutyInfo(that: MainPage) {
Taro.request({ Taro.request({
url: getUrl('/dutyinfo'), url: getUrl('/duty/info'),
method: 'GET', method: 'GET',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
}, },
}) })
.then((res) => { .then((res) => {
let former = that.state.rs;
if (!res.data.success) {
that.setState({
rs: former.trans(false),
});
return;
}
const data = res.data.data; const data = res.data.data;
if (data.isInDuty) { if (data.isInDuty) {
that.setState({ that.setState({
rs: former.trans(true),
dutyData: { dutyData: {
isInDuty: data.isInDuty, isInDuty: data.isInDuty,
inDutyCnt: data.inDutyCnt, inDutyCnt: data.inDutyCnt,
currentDuty: data.currentDuty, currentDuty: data.currentDuty,
place: data.place,
}, },
}); });
} else { } else {
that.setState({ that.setState({
rs: former.trans(true),
dutyData: { dutyData: {
isInDuty: data.isInDuty, isInDuty: data.isInDuty,
offDutyReason: data.offDutyReason, offDutyReason: data.offDutyReason,
dutyRecoverTime: data.dutyRecoverTime, dutyRecoverTime: data.dutyRecoverTime,
place: data.place,
}, },
}); });
} }
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err);
let former = that.state.rs;
that.setState({ that.setState({
rs: former.trans(false),
dutyData: { dutyData: {
isInDuty: false, isInDuty: false,
offDutyReason: '获取失败!Network Error!', offDutyReason: '获取失败!Network Error!',
dutyRecoverTime: '获取失败!Network Error!', dutyRecoverTime: '获取失败!Network Error!',
place: '204',
}, },
}); });
}); });
+33
View File
@@ -0,0 +1,33 @@
import TicketDetail from '@/pages/TicketDetail/TicketDetail';
import Taro from '@tarojs/taro';
import wechatUser from '@/wechat';
import { getUrl } from '.';
export function getDisable(that: TicketDetail, id: number) {
Taro.request({
url: getUrl('/tickets/info'),
method: 'GET',
data: {
id: id,
},
})
.then((res) => {
const data = res.data.data;
if (data.status === 3 || data.status === 5 || data.status === 7) {
that.setState({
isRetrieveDisable_main: true,
isCommentDisable_main: true,
});
}
if (wechatUser.getAccess()) {
if (data.workers.includes(wechatUser.getInfo().name)) {
that.setState({
isPickDisable_main: true,
});
}
}
})
.catch((reason) => {
console.error(reason);
});
}
+47
View File
@@ -0,0 +1,47 @@
import Taro from '@tarojs/taro';
import wechatUser, { UserInfo } from '@/wechat';
import { defaultAvatar } from '@/common';
import { getUrl } from '.';
import { getLocaleData } from './localeData';
export function getInfo() {
Taro.request({
url: getUrl('/member/login'),
method: 'POST',
data: {
token: wechatUser.getToken(),
},
})
.then((res) => {
const data = res.data.data;
if (res.data.success) {
wechatUser.setInfo(data as UserInfo);
wechatUser.setAccess(true);
} else {
Taro.request({
url: getUrl('/user/info'),
method: 'GET',
data: {
token: wechatUser.getToken(),
},
})
.then((re) => {
const info = re.data.data;
const userInfo: UserInfo = {
name: info.name,
phone: info.phone,
avatar: defaultAvatar,
};
console.log(userInfo);
wechatUser.setInfo(userInfo);
})
.catch((err) => {
console.log(err);
});
}
getLocaleData();
})
.catch((err) => {
console.log(err);
});
}
+3 -2
View File
@@ -1,5 +1,6 @@
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt, { Lang } from '@/plain-text'; import pt, { Lang } from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.'; import { getUrl } from '.';
export function setLocaleData(lang: Lang) { export function setLocaleData(lang: Lang) {
@@ -7,7 +8,7 @@ export function setLocaleData(lang: Lang) {
url: getUrl('/user/locale/update'), url: getUrl('/user/locale/update'),
method: 'POST', method: 'POST',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
lang: lang, lang: lang,
}, },
}).then((res) => { }).then((res) => {
@@ -20,7 +21,7 @@ export function getLocaleData() {
url: getUrl('/user/locale/get'), url: getUrl('/user/locale/get'),
method: 'GET', method: 'GET',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
}, },
}).then((res) => { }).then((res) => {
console.log(res.data); console.log(res.data);
+35
View File
@@ -0,0 +1,35 @@
import Taro from '@tarojs/taro';
import wechatUser from '@/wechat';
import { getUrl } from '.';
import { getLocaleData } from './localeData';
export function loginAte() {
Taro.login({
success: function (res) {
if (res.code) {
Taro.request({
url: getUrl('/login'),
method: 'POST',
data: {
code: res.code,
},
})
.then((re) => {
const data = re.data.data;
Taro.setStorage({
key: 'token',
data: data.token,
});
wechatUser.setToken(data.token);
getLocaleData();
})
.catch((err) => {
console.log(err);
});
getLocaleData();
} else {
console.log('Login Failed: ' + res.errMsg);
}
},
});
}
+48
View File
@@ -0,0 +1,48 @@
import MainPage from '@/pages/index';
import Taro from '@tarojs/taro';
import wechatUser from '@/wechat';
import { getUrl } from '.';
export function getMemberDutyInfo(that: MainPage) {
Taro.request({
url: getUrl('/member/duty/info'),
method: 'GET',
data: {
token: wechatUser.getToken(),
},
})
.then((res) => {
const data = res.data.data;
if (data.isInDuty) {
that.setState({
dutyData: {
isInDuty: data.isInDuty,
inDutyCnt: data.inDutyCnt,
currentDuty: data.currentDuty,
place: data.place,
},
inDutyCnt: data.inDutyCnt,
});
} else {
that.setState({
dutyData: {
isInDuty: data.isInDuty,
offDutyReason: data.offDutyReason,
dutyRecoverTime: data.dutyRecoverTime,
place: data.place,
},
});
}
})
.catch((err) => {
console.log(err);
that.setState({
dutyData: {
isInDuty: false,
offDutyReason: '获取失败!Network Error!',
dutyRecoverTime: '获取失败!Network Error!',
place: '204',
},
});
});
}
+89
View File
@@ -0,0 +1,89 @@
import UserMemberPage from '@/pages/user/member/member';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser, { UserInfo } from '@/wechat';
import { getUrl } from '.';
export function memberLogin(that: UserMemberPage) {
that.setState({
isLoading: true,
});
Taro.request({
url: getUrl('/member/login'),
method: 'POST',
data: {
token: wechatUser.getToken(),
name: that.state.stuid,
phone: that.state.passwd,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isLoading: false,
});
if (res.data.success) {
Taro.atMessage({
message: pt.get().button.loginText.success,
type: 'success',
});
wechatUser.setInfo(res.data.data as UserInfo);
wechatUser.setAccess(true);
Taro.reLaunch({
url: '/pages/index/index',
});
} else {
Taro.atMessage({
message: pt.get().button.loginText.fail,
type: 'error',
});
}
})
.catch((err) => {
console.log(err);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.loginText.error + err.toString(),
type: 'error',
});
});
}
export function memberLogout(that: UserMemberPage) {
that.setState({
isLoading: true,
});
Taro.request({
url: getUrl('/member/logout'),
method: 'POST',
data: {
token: wechatUser.getToken(),
},
})
.then((res) => {
console.log(res.data);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.logoutText.success,
type: 'success',
});
wechatUser.setAccess(false);
Taro.reLaunch({
url: '/pages/index/index',
});
})
.catch((err) => {
console.log(err);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.logoutText.error + err.toString(),
type: 'error',
});
});
}
+11 -3
View File
@@ -2,6 +2,8 @@ import MyTicketPage from '@/pages/user/myTicket/myTicket';
import { TicketListItem } from '@/components/TicketListItem/TicketListItem'; import { TicketListItem } from '@/components/TicketListItem/TicketListItem';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import moment from 'moment'; import moment from 'moment';
import { FixStatus } from '@/common';
import wechatUser from '@/wechat';
import { getUrl } from '.'; import { getUrl } from '.';
export function getMyTicketList(that: MyTicketPage) { export function getMyTicketList(that: MyTicketPage) {
@@ -9,7 +11,7 @@ export function getMyTicketList(that: MyTicketPage) {
url: getUrl('/user/mytickets'), url: getUrl('/user/mytickets'),
method: 'GET', method: 'GET',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
}, },
}) })
.then((res) => { .then((res) => {
@@ -23,13 +25,19 @@ export function getMyTicketList(that: MyTicketPage) {
that.setState({ that.setState({
rs: former.trans(true), rs: former.trans(true),
fixList: res.data.data.list.map( fixList: res.data.data.list.map(
(item) => (item: {
id: number;
device: string;
deviceModel: string;
status: FixStatus;
createdTime: moment.MomentInput;
}) =>
new TicketListItem( new TicketListItem(
item.id, item.id,
item.device, item.device,
item.deviceModel, item.deviceModel,
item.status, item.status,
moment(), moment(item.createdTime),
), ),
), ),
}); });
+46
View File
@@ -0,0 +1,46 @@
import TicketDetail from '@/pages/TicketDetail/TicketDetail';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
const reLaunchInterval = 1000;
export function pickTicket(that: TicketDetail) {
that.setState({
isPickLoading: true,
});
Taro.request({
url: getUrl('/tickets/pick'),
method: 'POST',
data: {
token: wechatUser.getToken(),
id: that.state.id,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isPickLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
setTimeout(() => {
Taro.reLaunch({
url: '/pages/TicketDetail/TicketDetail?id=' + that.state.id,
});
}, reLaunchInterval);
})
.catch((err) => {
console.log(err);
that.setState({
isPickLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+39
View File
@@ -0,0 +1,39 @@
import ReportPage from '@/pages/user/report/report';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
export function reportMessage(that: ReportPage) {
that.setState({
isLoading: true,
});
Taro.request({
url: getUrl('/report'),
method: 'POST',
data: {
token: wechatUser.getToken(),
report: that.state.report,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
})
.catch((err) => {
console.log(err);
that.setState({
isLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+46
View File
@@ -0,0 +1,46 @@
import TicketDetail from '@/pages/TicketDetail/TicketDetail';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
const reLaunchInterval = 1000;
export function retrieve(that: TicketDetail) {
that.setState({
isRetrieveLoading: true,
});
Taro.request({
url: getUrl('/tickets/retrieve'),
method: 'POST',
data: {
token: wechatUser.getToken(),
id: that.state.id,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isRetrieveLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
setTimeout(() => {
Taro.reLaunch({
url: '/pages/TicketDetail/TicketDetail?id=' + that.state.id,
});
}, reLaunchInterval);
})
.catch((err) => {
console.log(err);
that.setState({
isRetrieveLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+46
View File
@@ -0,0 +1,46 @@
import TicketDetail from '@/pages/TicketDetail/TicketDetail';
import Taro from '@tarojs/taro';
import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.';
const reLaunchInterval = 1000;
export function submitComment(that: TicketDetail) {
that.setState({
isCommentLoading: true,
});
Taro.request({
url: getUrl('/report'),
method: 'POST',
data: {
token: wechatUser.getToken(),
comment: that.state.comment,
},
})
.then((res) => {
console.log(res.data);
that.setState({
isCommentLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.success,
type: 'success',
});
setTimeout(() => {
Taro.reLaunch({
url: '/pages/TicketDetail/TicketDetail?id=' + that.state.id,
});
}, reLaunchInterval);
})
.catch((err) => {
console.log(err);
that.setState({
isCommentLoading: false,
});
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
+51 -1
View File
@@ -1,17 +1,50 @@
import RepairPage from '@/pages/repair/repair'; import RepairPage from '@/pages/repair/repair';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt from '@/plain-text'; import pt from '@/plain-text';
import wechatUser, { UserInfo } from '@/wechat';
import { defaultAvatar, tmplIds } from '@/common';
import { getUrl } from '.'; import { getUrl } from '.';
const relaunchInterval = 1000;
export function submitTicket(that: RepairPage) { export function submitTicket(that: RepairPage) {
that.setState({ that.setState({
isLoading: true, isLoading: true,
}); });
if (!wechatUser.getAccess()) {
const userInfo = wechatUser.getInfo();
if (userInfo.name == '' || userInfo.phone == '') {
Taro.request({
url: getUrl('/user/update'),
method: 'POST',
data: {
token: wechatUser.getToken(),
name: that.state.owner,
phone: that.state.phone,
},
})
.then(() => {
const userTicketInfo: UserInfo = {
name: that.state.owner,
phone: that.state.phone,
avatar: defaultAvatar,
};
wechatUser.setInfo(userTicketInfo);
})
.catch((err) => {
console.log(err);
Taro.atMessage({
message: pt.get().button.submitText.error + err.toString(),
type: 'error',
});
});
}
}
Taro.request({ Taro.request({
url: getUrl('/tickets/create'), url: getUrl('/tickets/create'),
method: 'POST', method: 'POST',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
type: that.state.type, type: that.state.type,
device: that.state.device, device: that.state.device,
deviceModel: that.state.deviceModel, deviceModel: that.state.deviceModel,
@@ -30,6 +63,23 @@ export function submitTicket(that: RepairPage) {
message: pt.get().button.submitText.success, message: pt.get().button.submitText.success,
type: 'success', type: 'success',
}); });
Taro.requestSubscribeMessage({
tmplIds: tmplIds,
success: function (re) {
console.log(re);
},
fail: function (err) {
console.log(err);
},
complete: function () {
setTimeout(() => {
Taro.reLaunch({
url: '/pages/repair/repair',
});
}, relaunchInterval);
},
entityIds: tmplIds,
});
}) })
.catch((err) => { .catch((err) => {
console.log(err); console.log(err);
+39 -9
View File
@@ -2,8 +2,21 @@ import { TicketInfo, TicketNote } from '@/pages/TicketDetail/TicketNote';
import DetailFramework from '@/components/DetailFramework/DetailFramework'; import DetailFramework from '@/components/DetailFramework/DetailFramework';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import moment from 'moment'; import moment from 'moment';
import { FixStatus } from '@/common';
import pt from '@/plain-text';
import { getUrl } from '.'; import { getUrl } from '.';
const mapStatusStep: Map<FixStatus, 0 | 1 | 2 | 3> = new Map([
[0, 0],
[1, 1],
[2, 2],
[3, 3],
[4, 2],
[5, 3],
[6, 2],
[7, 3],
]);
export function getTicketInfo(that: DetailFramework, id: number) { export function getTicketInfo(that: DetailFramework, id: number) {
Taro.request({ Taro.request({
url: getUrl('/tickets/info'), url: getUrl('/tickets/info'),
@@ -24,25 +37,42 @@ export function getTicketInfo(that: DetailFramework, id: number) {
id: data.id, id: data.id,
type: data.type, type: data.type,
device: data.device, device: data.device,
workers: data.workers,
deviceModel: data.deviceModel, deviceModel: data.deviceModel,
description: data.description, description: data.description,
createdTime: moment(data.createdTime as string), createdTime: moment(data.createdTime as string),
status: data.status, status: data.status,
info: {
phone: data.phone,
name: data.owner,
},
}; };
const notes: Array<TicketNote> = []; const notes: Array<TicketNote> = [];
data.notes.map((item) => { data.notes.map(
notes.push({ (item: {
id: item.id, avatar: string;
op: item.op, id: number;
type: item.type, op: string;
content: item.content, type: 0 | 1 | 2;
createdTime: moment(item.createdTime as string), content: string;
}); createdTime: string;
}); }) => {
notes.push({
avatar: item.avatar,
id: item.id,
op: item.op,
type: item.type,
content: item.content,
createdTime: moment(item.createdTime as string),
});
},
);
that.setState({ that.setState({
ticketInfo: ticketDetail, ticketInfo: ticketDetail,
notes: notes, notes: notes,
rs: former.trans(true), rs: former.trans(true),
current: mapStatusStep.get(data.status) || 0,
items: pt.get().ticketDetail.stepItems,
}); });
} }
}) })
+45
View File
@@ -0,0 +1,45 @@
import MainPage from '@/pages/index';
import Taro from '@tarojs/taro';
import { TicketListItem } from '@/components/TicketListItem/TicketListItem';
import moment from 'moment';
import wechatUser from '@/wechat';
import { getUrl } from '.';
export function getUncompletedTicketList(that: MainPage) {
Taro.request({
url: getUrl('/tickets/uncompleted'),
method: 'GET',
data: {
token: wechatUser.getToken(),
},
})
.then((res) => {
let former = that.state.rs;
if (!res.data.success) {
that.setState({
rs: former.trans(false),
});
return;
}
that.setState({
rs: former.trans(true),
fixList: res.data.data.list.map(
(item) =>
new TicketListItem(
item.id,
item.device,
item.deviceModel,
item.status,
moment(item.createdTime),
),
),
});
})
.catch((reason) => {
let former = that.state.rs;
that.setState({
rs: former.trans(false),
});
console.log(reason);
});
}
+2 -1
View File
@@ -1,6 +1,7 @@
import InformPage from '@/pages/user/inform/inform'; import InformPage from '@/pages/user/inform/inform';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import pt from '@/plain-text'; import pt from '@/plain-text';
import wechatUser from '@/wechat';
import { getUrl } from '.'; import { getUrl } from '.';
export function updateUserInfo(that: InformPage) { export function updateUserInfo(that: InformPage) {
@@ -11,7 +12,7 @@ export function updateUserInfo(that: InformPage) {
url: getUrl('/user/update'), url: getUrl('/user/update'),
method: 'POST', method: 'POST',
data: { data: {
token: 'token_test', token: wechatUser.getToken(),
name: that.state.name, name: that.state.name,
phone: that.state.phone, phone: that.state.phone,
}, },
+3
View File
@@ -0,0 +1,3 @@
export const randomInt = (floor: number, ceiling: number) => {
return Math.floor(Math.random() * (ceiling - floor + 1) + floor);
};
+25 -7
View File
@@ -1,12 +1,23 @@
import { defaultAvatar } from '@/common';
export interface UserInfo {
name: string;
phone: string;
avatar: string;
}
class WechatUser { class WechatUser {
private userInfo: any; private userInfo: UserInfo;
private isMember: boolean; private isMember: boolean;
hasUserInfo: boolean; private token: string;
constructor() { constructor() {
this.userInfo = ''; this.userInfo = {
this.hasUserInfo = false; name: '',
this.isMember = true; phone: '',
avatar: defaultAvatar,
};
this.isMember = false;
} }
getAccess() { getAccess() {
@@ -17,14 +28,21 @@ class WechatUser {
return this.userInfo; return this.userInfo;
} }
setInfo(userInfo: any) { getToken() {
return this.token;
}
setInfo(userInfo: UserInfo) {
this.userInfo = userInfo; this.userInfo = userInfo;
this.hasUserInfo = true;
} }
setAccess(isMember: boolean) { setAccess(isMember: boolean) {
this.isMember = isMember; this.isMember = isMember;
} }
setToken(token: string) {
this.token = token;
}
} }
const wechatUser = new WechatUser(); const wechatUser = new WechatUser();