acceptIndex.uvue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. <template>
  2. <view class="detail-page">
  3. <scroll-view class="detail-content" :scroll-y="true">
  4. <!-- 工单信息 -->
  5. <view class="info-section">
  6. <view class="section-title">
  7. <text class="section-title-text">工单信息</text>
  8. </view>
  9. <view class="info-card">
  10. <view class="info-item">
  11. <text class="info-label">工单编码</text>
  12. <text class="info-value">{{ detailData.workOrderProjectNo ?? '' }}</text>
  13. </view>
  14. <view class="info-item">
  15. <text class="info-label">工单类型</text>
  16. <text class="info-value">{{ detailData.orderType == 1 ? '维修工单' : '维保工单' }}</text>
  17. </view>
  18. <view class="info-item">
  19. <text class="info-label">风机编号</text>
  20. <text class="info-value">{{ detailData.pcsDeviceName ?? '' }}</text>
  21. </view>
  22. <view class="info-item">
  23. <text class="info-label">维保中心</text>
  24. <text class="info-value">{{ detailData.gxtCenter ?? '' }}</text>
  25. </view>
  26. <view class="info-item">
  27. <text class="info-label">场站</text>
  28. <text class="info-value">{{ detailData.pcsStationName ?? '' }}</text>
  29. </view>
  30. <!-- <view class="info-item">
  31. <text class="info-label">品牌</text>
  32. <text class="info-value">{{ detailData.model ?? '' }}</text>
  33. </view> -->
  34. <view class="info-item">
  35. <text class="info-label">机型</text>
  36. <text class="info-value">{{ detailData.brand ?? '' }} {{ detailData.model ?? '' }}</text>
  37. </view>
  38. <view class="info-item">
  39. <text class="info-label">下发时间</text>
  40. <text class="info-value">{{ detailData.assignTime ?? '' }}</text>
  41. </view>
  42. <view class="info-item" v-if="detailData.orderType == 2">
  43. <text class="info-label">MIS工单编码</text>
  44. <text class="info-value">{{ detailData.misNo ?? '' }}</text>
  45. </view>
  46. <view class="info-item" v-if="detailData.orderType == 2">
  47. <text class="info-label">维保内容</text>
  48. <text class="info-value">{{ detailData.content ?? '' }}</text>
  49. </view>
  50. <view class="info-item" v-if="detailData.orderType == 1">
  51. <text class="info-label">故障代码</text>
  52. <text class="info-value">{{ detailData.faultCode ?? '' }}</text>
  53. </view>
  54. <view class="info-item" v-if="detailData.orderType == 1">
  55. <text class="info-label">故障信息</text>
  56. <text class="info-value">{{ detailData.faultBarcode ?? '' }}</text>
  57. </view>
  58. <!-- <view class="info-item" v-if="detailData.orderType == 1">
  59. <text class="info-label">工作负责人</text>
  60. <view class="form-picker" @click="showLeaderPicker = true">
  61. <view class="picker-display">
  62. <text v-if="selectedTeamLeaderName" class="selected-value">{{ selectedTeamLeaderName }}</text>
  63. <text v-else class="placeholder">请选择工作负责人</text>
  64. <text class="arrow">▼</text>
  65. </view>
  66. </view>
  67. </view> -->
  68. </view>
  69. </view>
  70. <!-- <view class="info-section">
  71. <view class="section-title">
  72. <text class="section-title-text">工作负责人</text>
  73. </view>
  74. <view class="info-card">
  75. <view class="info-item">
  76. <input class="input" type="text" placeholder="请输入工作负责人" v-model="teamLeaderName" />
  77. </view>
  78. </view>
  79. </view> -->
  80. <!-- 工作负责人选择 -->
  81. <view class="info-section">
  82. <view class="section-title">
  83. <text class="section-title-text">工作负责人</text>
  84. </view>
  85. <view class="info-card">
  86. <view class="form-item">
  87. <!-- <text class="form-label required">工作负责人</text> -->
  88. <view class="form-picker" @click="showLeaderPicker = true">
  89. <view class="picker-display">
  90. <text v-if="selectedTeamLeaderName" class="selected-value">{{ selectedTeamLeaderName }}</text>
  91. <text v-else class="placeholder">请选择工作负责人</text>
  92. <text class="arrow">▼</text>
  93. </view>
  94. </view>
  95. </view>
  96. </view>
  97. </view>
  98. <!-- 自定义选择器弹窗 -->
  99. <view v-if="showLeaderPicker" class="picker-modal">
  100. <view class="modal-mask" @click="showLeaderPicker = false"></view>
  101. <view class="modal-content">
  102. <view class="modal-header">
  103. <text class="modal-title">选择工作负责人</text>
  104. <text class="modal-close" @click="showLeaderPicker = false">取消</text>
  105. </view>
  106. <scroll-view class="modal-body" scroll-y="true">
  107. <view
  108. v-for="(option, index) in teamLeaderList"
  109. :key="index"
  110. class="picker-option"
  111. :class="{ 'selected': index === selectedTeamLeaderIndex }"
  112. @click="selectLeaderManually(index)"
  113. >
  114. <!-- <text class="option-text">{{ option.label }}</text>
  115. <text class="option-text">{{ option.value }}</text> -->
  116. <text class="option-text">{{ option.nickName }}</text>
  117. <text class="option-text">{{ option.deptName }}</text>
  118. <text v-if="index === selectedTeamLeaderIndex" class="option-check">✓</text>
  119. </view>
  120. </scroll-view>
  121. </view>
  122. </view>
  123. <!-- 工单流转 -->
  124. <!-- <view class="info-section">
  125. <view class="section-title">
  126. <text class="section-title-text">工单流转</text>
  127. </view>
  128. <view class="info-card" v-if="detailData.workOrderFlowList != null && detailData.workOrderFlowList.length > 0">
  129. <view class="flow-item" v-for="(flow, index) in detailData.workOrderFlowList" :key="index">
  130. <view class="flow-header">
  131. <text class="flow-operator">{{ flow.operatorName ?? '未知操作人' }}</text>
  132. <text class="flow-time">{{ flow.actionTime ?? '' }}</text>
  133. </view>
  134. <view class="flow-content">
  135. <text class="flow-action">{{ getActionTypeName(flow.actionType) }}</text>
  136. <text class="flow-remark" v-if="flow.actionRemark">{{ flow.actionRemark }}</text>
  137. </view>
  138. </view>
  139. </view>
  140. <view class="info-card" v-else>
  141. <view class="no-data">暂无流转记录</view>
  142. </view>
  143. </view> -->
  144. </scroll-view>
  145. <!-- 接单按钮 -->
  146. <view class="accept-button-container" v-if="checkPermi(['gxt:maintenance:order:accept','gxt:repairOrder:accept'])">
  147. <button class="accept-button" @click="handleAcceptOrder">接 单</button>
  148. </view>
  149. <!-- 加载中状态 -->
  150. <view v-if="loading" class="loading-mask">
  151. <text class="loading-text">加载中...</text>
  152. </view>
  153. </view>
  154. </template>
  155. <script setup lang="uts">
  156. import { ref } from 'vue'
  157. import type { acceptOrderInfo2 } from '../../../types/order'
  158. import type { WorkOrderFlow } from '../../../types/flow'
  159. import { getOrderInfoById, getRepairOrderInfoById, acceptOrder } from '../../../api/order/detail'
  160. import type { SysDictData } from '../../../types/dict'
  161. import { getDictDataByType } from '../../../api/dict/index'
  162. import { getUserList } from '../../../api/user/list'
  163. import type { UserInfo } from '../../../types/user'
  164. import {checkPermi} from '../../../utils/storage'
  165. const teamLeaderName = ref<string>("")
  166. const statusDictList = ref<SysDictData[]>([]) // 工单状态字典列表
  167. // 添加字典加载状态
  168. const dictLoaded = ref<boolean>(false)
  169. // 详情数据
  170. const detailData = ref<acceptOrderInfo2>({
  171. orderType: 0,
  172. id: 0,
  173. teamLeaderId: 0,
  174. acceptUserId: 0,
  175. teamLeaderName: null,
  176. acceptUserName: null,
  177. acceptTime: null,
  178. assignTime: null,
  179. assignUserName: null,
  180. status: 0,
  181. workOrderProjectNo: null,
  182. workOrderStatus: null,
  183. gxtCenterId: 0,
  184. gxtCenter: null,
  185. pcsStationId: 0,
  186. pcsStationName: null,
  187. pcsDeviceId: 0,
  188. pcsDeviceName: null,
  189. brand: null,
  190. model: null,
  191. createTime: null,
  192. workOrderFlowList: null,
  193. suspendReason: null,
  194. rejectionReason: null,
  195. misNo: null,
  196. content: null,
  197. faultCode: null,
  198. faultBarcode: null
  199. })
  200. // 选择器选项类型
  201. type PickerOption = {
  202. label: string
  203. value: string
  204. }
  205. // 选中的负责人信息
  206. const selectedTeamLeaderName = ref<string>('')
  207. const selectedTeamLeaderIndex = ref<number>(-1)
  208. const showLeaderPicker = ref<boolean>(false)
  209. const teamLeaderList = ref<UserInfo[]>([])
  210. // 获取负责人列表(使用用户列表接口)
  211. const loadTeamLeaderList = async (): Promise<void> => {
  212. try {
  213. const deptId = detailData.value.gxtCenterId
  214. const result = await getUserList(-1)
  215. const resultObj = result as UTSJSONObject
  216. if (resultObj['code'] == 200) {
  217. const data = resultObj['data'] as any[]
  218. const leaders: UserInfo[] = []
  219. if (data.length > 0) {
  220. for (let i = 0; i < data.length; i++) {
  221. const item = data[i] as UTSJSONObject
  222. const deptObj = item['dept'] as UTSJSONObject
  223. let leader: UserInfo = {
  224. userName: item['userName'] as string,
  225. nickName: item['nickName'] as string,
  226. userId: new Int32Array([item['userId'] != null ? (item['userId'] as number) : 0]),
  227. phone: item['phonenumber'] as string,
  228. deptName : (deptObj['deptName'] != null) ? (deptObj['deptName'] as string) : ''
  229. }
  230. leaders.push(leader)
  231. }
  232. }
  233. teamLeaderList.value = leaders
  234. }
  235. } catch (e: any) {
  236. console.error('获取负责人列表失败:', e.message)
  237. }
  238. }
  239. // 手动选择负责人
  240. const selectLeaderManually = (index: number): void => {
  241. selectedTeamLeaderIndex.value = index
  242. if (index >= 0 && index < teamLeaderList.value.length) {
  243. const selectedOption = teamLeaderList.value[index]
  244. selectedTeamLeaderName.value = selectedOption.nickName
  245. detailData.value.teamLeaderId = selectedOption.userId[0] as number
  246. detailData.value.teamLeaderName = selectedOption.nickName
  247. }
  248. showLeaderPicker.value = false
  249. }
  250. // 获取工单状态字典列表
  251. const loadStatusDictList = async (): Promise<void> => {
  252. try {
  253. const result = await getDictDataByType('gxt_repair_order_flow_action_type')
  254. const resultObj = result as UTSJSONObject
  255. if (resultObj['code'] == 200) {
  256. const data = resultObj['data'] as any[]
  257. const dictData: SysDictData[] = []
  258. if (data.length > 0) {
  259. for (let i = 0; i < data.length; i++) {
  260. const item = data[i] as UTSJSONObject
  261. // 只提取需要的字段
  262. const dictItem: SysDictData = {
  263. dictValue: item['dictValue'] as string | null,
  264. dictLabel: item['dictLabel'] as string | null,
  265. dictCode: null,
  266. dictSort: null,
  267. dictType: null,
  268. cssClass: null,
  269. listClass: null,
  270. isDefault: null,
  271. status: null,
  272. default: null,
  273. createTime: null,
  274. remark: null
  275. }
  276. dictData.push(dictItem)
  277. }
  278. }
  279. statusDictList.value = dictData
  280. dictLoaded.value = true
  281. }
  282. } catch (e: any) {
  283. console.error('获取工单状态字典失败:', e.message)
  284. dictLoaded.value = true
  285. }
  286. }
  287. // 处理接单操作
  288. const handleAcceptOrder = async (): Promise<void> => {
  289. if (selectedTeamLeaderName.value.trim() === '') {
  290. uni.showToast({
  291. title: '请选择工作负责人',
  292. icon: 'none'
  293. })
  294. return
  295. }
  296. // const subOrder = {
  297. // id: detailData.value.id,
  298. // orderType: detailData.value.orderType,
  299. // teamLeaderId: (selectedTeamLeaderId.value != null && selectedTeamLeaderId.value.length > 0) ? parseInt(selectedTeamLeaderId.value) : 0,
  300. // teamLeaderName: selectedTeamLeaderName.value,
  301. // workOrderProjectNo: detailData.value.workOrderProjectNo,
  302. // // gxtRepairOrder:
  303. // } as UTSJSONObject
  304. detailData.value.workOrderStatus = 'to_finish'
  305. try {
  306. const result = await acceptOrder(detailData.value)
  307. const resultObj = result as UTSJSONObject
  308. const code = resultObj['code'] as number
  309. if (code == 200) {
  310. uni.showToast({
  311. title: '接单成功',
  312. icon: 'success'
  313. })
  314. // 使用事件总线通知列表页面刷新
  315. uni.$emit('refreshOrderList', {})
  316. // 通知首页刷新待接单数量
  317. uni.$emit('refreshAssignedCount')
  318. // 接单成功后返回上一页
  319. setTimeout(() => {
  320. uni.navigateBack()
  321. }, 1000)
  322. }
  323. } catch (error) {
  324. console.error('请求失败:', error);
  325. }
  326. }
  327. const loading = ref<boolean>(false)
  328. // 获取操作类型名称
  329. const getActionTypeName = (item: string | null): string | null => {
  330. if (item == null) return ''
  331. // const orderInfoItem = item as orderInfo
  332. const rawStatus = item
  333. if (rawStatus==null) return ''
  334. // 如果字典尚未加载,返回原始值
  335. if (!dictLoaded.value) {
  336. return rawStatus
  337. }
  338. // 查找字典中对应的标签
  339. const dictItem = statusDictList.value.find(dict => dict.dictValue == rawStatus)
  340. return dictItem!=null ? dictItem.dictLabel : rawStatus
  341. }
  342. // 加载详情数据
  343. const loadDetail = async (id: string, orderType?: number): Promise<void> => {
  344. try {
  345. loading.value = true
  346. let result: any;
  347. // 根据orderType决定调用哪个API
  348. if (orderType == 1) {
  349. // 维修工单
  350. result = await getRepairOrderInfoById(id)
  351. } else {
  352. // 维保工单
  353. result = await getOrderInfoById(id)
  354. }
  355. // 提取响应数据
  356. const resultObj = result as UTSJSONObject
  357. const code = resultObj['code'] as number
  358. const data = resultObj['data'] as UTSJSONObject | null
  359. if (code == 200 && data != null) {
  360. // 处理工单流转列表
  361. let workOrderFlowList: WorkOrderFlow[] | null = null
  362. let flowList: UTSJSONObject[] = []
  363. if (orderType == 1) {
  364. // 维修工单
  365. flowList = data['repairOrderFlowList'] as UTSJSONObject[]
  366. } else {
  367. // 维保工单
  368. flowList = data['workOrderFlowList'] as UTSJSONObject[]
  369. }
  370. if (flowList.length > 0) {
  371. workOrderFlowList = []
  372. for (let i = 0; i < flowList.length; i++) {
  373. const flowItem = flowList[i]
  374. const flow: WorkOrderFlow = {
  375. id: flowItem['id'] as Number,
  376. orderId: flowItem['orderId'] as Number,
  377. orderCode: flowItem['orderCode'] as string,
  378. actionType: flowItem['actionType'] as string,
  379. fromStatus: flowItem['fromStatus'] as string | null,
  380. toStatus: flowItem['toStatus'] as string,
  381. operatorId: flowItem['operatorId'] as Number | null,
  382. operatorName: flowItem['operatorName'] as string | null,
  383. actionTime: flowItem['actionTime'] as string,
  384. actionRemark: flowItem['actionRemark'] as string | null,
  385. createBy: flowItem['createBy'] as string | null,
  386. createTime: flowItem['createTime'] as string | null
  387. }
  388. workOrderFlowList.push(flow)
  389. }
  390. }
  391. // 转换数据
  392. const orderDtail: acceptOrderInfo2 = {
  393. orderType: data['orderType'] as Number,
  394. id: data['id'] as Number,
  395. teamLeaderId: data['teamLeaderId'] != null ? (data['teamLeaderId'] as Number) : 0,
  396. acceptUserId: data['acceptUserId'] != null ? (data['acceptUserId'] as Number) : 0,
  397. teamLeaderName: data['teamLeaderName'] as string | null,
  398. acceptUserName: data['acceptUserName'] as string | null,
  399. acceptTime: data['acceptTime'] as string | null,
  400. assignTime: data['assignTime'] as string | null,
  401. assignUserName: data['assignUserName'] as string | null,
  402. status: (data['status']==null)?0:data['status'] as Number,
  403. workOrderProjectNo: data['workOrderProjectNo'] as string | null,
  404. workOrderStatus: data['workOrderStatus'] as string | null,
  405. gxtCenterId: data['gxtCenterId'] as Number | 0,
  406. gxtCenter: data['gxtCenter'] as string | null,
  407. pcsStationId: data['pcsStationId'] as Number | 0,
  408. pcsStationName: data['pcsStationName'] as string | null,
  409. pcsDeviceId: data['pcsDeviceId'] as Number | 0,
  410. pcsDeviceName: data['pcsDeviceName'] as string | null,
  411. brand: data['brand'] as string | null,
  412. model: data['model'] as string | null,
  413. createTime: data['createTime'] as string | null,
  414. workOrderFlowList: workOrderFlowList,
  415. suspendReason: data['suspendReason'] as string | null,
  416. rejectionReason: data['rejectionReason'] as string | null,
  417. misNo: data['misNo'] as string | null,
  418. content: data['content'] as string | null,
  419. faultCode: data['faultCode'] as string | null,
  420. faultBarcode: data['faultBarcode'] as string | null
  421. }
  422. detailData.value = orderDtail
  423. // 如果工单数据中已有负责人信息,设置到输入框中
  424. if (orderDtail.teamLeaderName != null && orderDtail.teamLeaderName.length > 0) {
  425. teamLeaderName.value = orderDtail.teamLeaderName as string
  426. }
  427. loadTeamLeaderList()
  428. } else {
  429. const msg = resultObj['msg'] as string | null
  430. uni.showToast({
  431. title: msg ?? '加载失败',
  432. icon: 'none'
  433. })
  434. }
  435. } catch (e: any) {
  436. uni.showToast({
  437. title: e.message ?? '加载失败',
  438. icon: 'none'
  439. })
  440. } finally {
  441. loading.value = false
  442. }
  443. }
  444. // 页面加载
  445. onLoad((options: any) => {
  446. const params = options as UTSJSONObject
  447. const id = params['id'] as string | null
  448. const orderTypeParam = params['orderType'] as string | null
  449. if (id != null && orderTypeParam != null) {
  450. // 先尝试从参数中获取orderType
  451. const orderTypeNumber = parseInt(orderTypeParam)
  452. loadDetail(id, orderTypeNumber)
  453. }
  454. })
  455. // 初始化
  456. onMounted(() => {
  457. loadStatusDictList()
  458. })
  459. </script>
  460. <style lang="scss">
  461. .detail-page {
  462. flex: 1;
  463. background-color: #e8f0f9;
  464. }
  465. .detail-content {
  466. flex: 1;
  467. padding: 20rpx 0;
  468. }
  469. .info-section {
  470. margin: 0 30rpx 24rpx;
  471. .section-title {
  472. position: relative;
  473. padding-left: 20rpx;
  474. margin-bottom: 20rpx;
  475. &::before {
  476. // content: '';
  477. position: absolute;
  478. left: 0;
  479. top: 50%;
  480. transform: translateY(-50%);
  481. width: 8rpx;
  482. height: 32rpx;
  483. background-color: #007aff;
  484. border-radius: 4rpx;
  485. }
  486. &-text {
  487. font-size: 32rpx;
  488. font-weight: bold;
  489. color: #333333;
  490. }
  491. }
  492. .info-card {
  493. background-color: #ffffff;
  494. border-radius: 16rpx;
  495. padding: 30rpx;
  496. .info-item {
  497. flex-direction: row;
  498. padding: 20rpx 0;
  499. border-bottom: 1rpx solid #f0f0f0;
  500. &:last-child {
  501. border-bottom: none;
  502. }
  503. &.full-width {
  504. flex-direction: column;
  505. .info-label {
  506. margin-bottom: 12rpx;
  507. }
  508. .info-value {
  509. line-height: 44rpx;
  510. }
  511. }
  512. .info-label {
  513. width: 240rpx;
  514. font-size: 28rpx;
  515. color: #666666;
  516. white-space: nowrap;
  517. }
  518. .info-value {
  519. flex: 1;
  520. font-size: 28rpx;
  521. color: #333333;
  522. text-align: right;
  523. &.highlight {
  524. color: #007aff;
  525. font-weight: bold;
  526. }
  527. &.input {
  528. text-align: left;
  529. border: 1rpx solid #e0e0e0;
  530. border-radius: 8rpx;
  531. padding: 10rpx;
  532. }
  533. }
  534. }
  535. .flow-item {
  536. padding: 20rpx 0;
  537. border-bottom: 1rpx solid #f0f0f0;
  538. &:last-child {
  539. border-bottom: none;
  540. }
  541. .flow-header {
  542. flex-direction: row;
  543. justify-content: space-between;
  544. margin-bottom: 10rpx;
  545. .flow-operator {
  546. font-size: 28rpx;
  547. color: #333333;
  548. font-weight: bold;
  549. }
  550. .flow-time {
  551. font-size: 24rpx;
  552. color: #999999;
  553. }
  554. }
  555. .flow-content {
  556. flex-direction: column;
  557. .flow-action {
  558. font-size: 26rpx;
  559. color: #666666;
  560. margin-bottom: 8rpx;
  561. }
  562. .flow-remark {
  563. font-size: 24rpx;
  564. color: #999999;
  565. background-color: #f5f5f5;
  566. padding: 10rpx;
  567. border-radius: 8rpx;
  568. }
  569. }
  570. }
  571. .no-data {
  572. text-align: center;
  573. padding: 40rpx 0;
  574. font-size: 28rpx;
  575. color: #999999;
  576. }
  577. }
  578. }
  579. .accept-button-container {
  580. padding: 30rpx 30rpx 50rpx;
  581. background-color: #ffffff;
  582. .accept-button {
  583. width: 100%;
  584. height: 80rpx;
  585. background-color: #007aff;
  586. color: #ffffff;
  587. font-size: 32rpx;
  588. border-radius: 16rpx;
  589. border: none;
  590. &:active {
  591. background-color: #0062cc;
  592. }
  593. }
  594. }
  595. .loading-mask {
  596. position: absolute;
  597. top: 0;
  598. left: 0;
  599. right: 0;
  600. bottom: 0;
  601. justify-content: center;
  602. align-items: center;
  603. background-color: rgba(0, 0, 0, 0.3);
  604. .loading-text {
  605. padding: 30rpx 60rpx;
  606. background-color: rgba(0, 0, 0, 0.7);
  607. color: #ffffff;
  608. font-size: 28rpx;
  609. border-radius: 12rpx;
  610. }
  611. }
  612. .picker-modal {
  613. position: fixed;
  614. top: 0;
  615. left: 0;
  616. right: 0;
  617. bottom: 0;
  618. z-index: 1000;
  619. }
  620. .modal-mask {
  621. position: absolute;
  622. top: 0;
  623. left: 0;
  624. right: 0;
  625. bottom: 0;
  626. background-color: rgba(0, 0, 0, 0.5);
  627. }
  628. .modal-content {
  629. position: absolute;
  630. bottom: 0;
  631. left: 0;
  632. right: 0;
  633. background-color: #ffffff;
  634. border-top-left-radius: 16rpx;
  635. border-top-right-radius: 16rpx;
  636. max-height: 700rpx;
  637. }
  638. .modal-header {
  639. flex-direction: row;
  640. justify-content: space-between;
  641. align-items: center;
  642. padding: 30rpx;
  643. border-bottom: 1rpx solid #f0f0f0;
  644. }
  645. .modal-title {
  646. font-size: 32rpx;
  647. font-weight: bold;
  648. color: #333333;
  649. }
  650. .modal-close {
  651. font-size: 28rpx;
  652. color: #007aff;
  653. }
  654. .modal-body {
  655. max-height: 600rpx;
  656. }
  657. .picker-option {
  658. flex-direction: row;
  659. justify-content: space-between;
  660. align-items: center;
  661. padding: 24rpx 30rpx;
  662. border-bottom: 1rpx solid #f0f0f0;
  663. }
  664. .picker-option.selected {
  665. background-color: #f8f9fa;
  666. }
  667. .option-text {
  668. font-size: 28rpx;
  669. color: #333333;
  670. }
  671. .option-check {
  672. font-size: 28rpx;
  673. color: #007aff;
  674. }
  675. .form-picker {
  676. flex: 1;
  677. }
  678. .picker-display {
  679. flex-direction: row;
  680. justify-content: space-between;
  681. align-items: center;
  682. min-height: 40rpx;
  683. }
  684. .selected-value {
  685. font-size: 28rpx;
  686. color: #333333;
  687. }
  688. .placeholder {
  689. font-size: 28rpx;
  690. color: #999999;
  691. }
  692. .arrow {
  693. font-size: 24rpx;
  694. color: #999999;
  695. margin-left: 12rpx;
  696. }
  697. </style>