detail.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. <template>
  2. <view v-if="time">
  3. <view style="background-color: #fff;padding: 20rpx 0;">
  4. <up-steps :current="current" dot activeColor="#0279FE">
  5. <up-steps-item v-for="item in steps" :key="item.title" :title="item.title" />
  6. </up-steps>
  7. </view>
  8. <view class="main">
  9. <view class="billno" style="margin-bottom: -24rpx;">
  10. 工单编号:{{ detail.billno }}
  11. </view>
  12. <view class="row">
  13. <view class="label col-center">服务类型</view>
  14. <view class="servicetype"
  15. :style="{ 'background': { '安装': '#70B603', '维修': '#D9001B', '清洁': '#3874F6', '清洗': '#3874F6' }[detail.servicetype] || '#999999' }">
  16. {{ detail.servicetype || '--' }}</view>
  17. </view>
  18. <view class="row">
  19. <view class="label">产品品类</view>
  20. <view class="value">{{ detail.class1 || '--' }}</view>
  21. </view>
  22. <view class="row" v-if="detail.servicetype == '维修'">
  23. <view class="label">故障类型</view>
  24. <view class="value">{{ detail.reason || '--' }}</view>
  25. </view>
  26. <view class="row">
  27. <view class="label">服务地址</view>
  28. <view class="value">{{ detail.province + detail.city + detail.county + detail.address || '--' }}</view>
  29. </view>
  30. <view class="row" style="align-items: center;">
  31. <view class="label justify">联系人</view>
  32. <view class="value phonenumber">{{ detail.scenecontact || '--' }}
  33. <block v-if="detail.scenecontactphonenumber">
  34. <text style="margin: 0 20rpx 0 10rpx;">
  35. {{ detail.scenecontactphonenumber }}
  36. </text>
  37. <My-button :customStyle="{
  38. width: '142rpx',
  39. height: '48rpx',
  40. 'background-color': '#FFFFFF',
  41. 'color': '#3874F6',
  42. borderRadius: '10rpx'
  43. }" :frontIconStyle="{
  44. marginRight: '6rpx',
  45. }" frontIcon="icon-bodadianhua1" text="电话" :phonenumber="detail.scenecontactphonenumber" />
  46. </block>
  47. </view>
  48. </view>
  49. <view class="row">
  50. <view class="label">派单日期</view>
  51. <view class="value">{{ detail.createdate || '--' }}</view>
  52. </view>
  53. <view class="row">
  54. <view class="label">服务需求</view>
  55. <view class="value">{{ detail.remarks || '--' }}</view>
  56. </view>
  57. <up-transition :show="transition">
  58. <view class="transition">
  59. <up-divider />
  60. <view class="row" v-if="detail.enterprisename">
  61. <view class="label justify">销售商</view>
  62. <view class="value">{{ detail.enterprisename || '--' }}</view>
  63. </view>
  64. <view class="row" v-if="detail.itemsText.length">
  65. <view class="label">产品信息</view>
  66. <view class="value">
  67. <view class="col-center" v-for="(item, index) in detail.itemsText" :key="index">
  68. <view class="value"><text v-if="detail.itemsText.length != 1">{{ index + 1 }}. </text>{{
  69. item }}
  70. </view>
  71. </view>
  72. </view>
  73. </view>
  74. <view class="row" v-if="detail.sku">
  75. <view class="label justify">序列号</view>
  76. <view class="value">{{ detail.sku || '--' }}</view>
  77. </view>
  78. <view class="row" v-if="detail.customername || detail.customerphonenumber"
  79. style="align-items: center;">
  80. <view class="label justify">客户信息</view>
  81. <view class="value phonenumber">{{ detail.customername || '' }}
  82. <block v-if="detail.customerphonenumber">
  83. <text style="margin: 0 20rpx 0 10rpx;">
  84. {{ detail.customerphonenumber }}
  85. </text>
  86. <My-button :customStyle="{
  87. width: '142rpx',
  88. height: '48rpx',
  89. 'background-color': '#FFFFFF',
  90. 'color': '#3874F6',
  91. borderRadius: '10rpx'
  92. }" frontIcon="icon-bodadianhua1" text="电话" :phonenumber="detail.customerphonenumber" />
  93. </block>
  94. </view>
  95. </view>
  96. <view class="row" v-if="detail.servicetype !== '安装' && detail.cardno">
  97. <view class="label">保修信息</view>
  98. <view class="value">
  99. <text :style="{ color: detail.inqualityguaranteeperiod ? '#70B603' : '#D9001B' }"
  100. style="margin-right: 0rpx;">
  101. {{ detail.inqualityguaranteeperiod ? '在保' : '已过保' }}
  102. </text>
  103. {{ detail.cardno || '' }}
  104. <view v-if="detail.cardno" style="margin-top: 20rpx;">
  105. {{ item.begdate || '' }} - {{ item.enddate || '' }}
  106. </view>
  107. </view>
  108. </view>
  109. </view>
  110. </up-transition>
  111. <block v-if="detail.status == '进行中'">
  112. <view style="height: 40rpx;" />
  113. <view class="changeTransition" hover-class="navigator-hover" @click="transition = !transition">
  114. 详细信息
  115. <view class="iconfont icon-dianjizhankai" :class="transition ? 'shrink' : ''" />
  116. </view>
  117. </block>
  118. <!-- 底部按钮 -->
  119. <view v-if="detail.status == '待接单'" class="but-box">
  120. <view class="but-box-item" v-if="detail.customerphonenumber">
  121. <My-button :customStyle="{
  122. 'background-color': '#FFFFFF',
  123. 'color': '#3874F6',
  124. }" frontIcon="icon-bodadianhua1" text="电话" :phonenumber="detail.customerphonenumber" />
  125. </view>
  126. <view class="but-box-item" @click="takeOrderShow = true">
  127. <My-button frontIcon="icon-dianhua" text="接单" />
  128. <up-modal negativeTop="100" :show="takeOrderShow" title="是否确认接单?" showCancelButton
  129. @confirm="takeOrders" @cancel="takeOrderShow = false" ref="uModal"
  130. :asyncClose="true"></up-modal>
  131. </view>
  132. </view>
  133. <!-- 底部按钮 -->
  134. <view v-else-if="detail.status == '待开始'" class="but-box">
  135. <view class="but-box-item" @click="toChangeMsg">
  136. <My-button :customStyle="{
  137. 'background-color': '#FFFFFF',
  138. 'color': '#3874F6',
  139. }" text="信息修改" />
  140. </view>
  141. <view class="but-box-item" @click="!detail.sku ? toCMTips() : confirmStartShow = true">
  142. <My-button text="确认开始" />
  143. <up-modal negativeTop="100" :show="confirmStartShow" showCancelButton @confirm="confirmStart"
  144. @cancel="confirmStartShow = false" ref="uModal" :asyncClose="true">
  145. <view class="slot-content">
  146. <view>
  147. 请仔细核对服务信息和客户信息
  148. </view>
  149. <view style="margin-top: 20rpx;">
  150. 开始工单后确认信息将不可修改!
  151. </view>
  152. </view>
  153. </up-modal>
  154. </view>
  155. </view>
  156. </view>
  157. <view class="main" v-if="current >= 2 && detail.nodes.length" style="padding: 30rpx;">
  158. <nodes ref="Nodes" :nodes="detail.nodes" />
  159. <view v-if="detail.status == '进行中'" style='width: 60%;margin: 40rpx auto 0;padding-bottom: 30rpx;'
  160. @click="submit"><My-button text="完工提交" />
  161. </view>
  162. </view>
  163. </view>
  164. <view style="height: 50px;" />
  165. </template>
  166. <script setup>
  167. import { ref, reactive, getCurrentInstance } from 'vue';
  168. const { $Http } = getCurrentInstance().proxy;
  169. import { onLoad, onShow, onUnload } from '@dcloudio/uni-app';
  170. import nodes from './modules/nodes.vue';
  171. const transition = ref(true);
  172. const Nodes = ref(null);
  173. const current = ref(-1);
  174. const steps = reactive([
  175. { title: '接单', value: '待接单' },
  176. { title: '开始', value: '待开始' },
  177. { title: '进行中', value: '进行中' },
  178. { title: '提交', value: '提交' },
  179. { title: '完工', value: '已完成' }
  180. ]);
  181. let sa_workorderid = 0;
  182. onLoad((options) => {
  183. sa_workorderid = options.id;
  184. });
  185. onUnload(() => {
  186. delete $Http.content1
  187. });
  188. const time = ref(new Date().getTime());
  189. onShow(() => {
  190. getDetail()
  191. })
  192. let detail = reactive({
  193. itemsText: [],
  194. servicetype: ""
  195. });
  196. function getDetail() {
  197. $Http.basic({ "id": "20230208140103", "content": { "nocache": true, sa_workorderid } }).then(res => {
  198. console.log("工单详情", res)
  199. $Http.content1 = {
  200. itemid: res.data.itemid,
  201. sku: res.data.sku,
  202. sys_enterpriseid: res.data.sys_enterpriseid,
  203. sa_workorderid: res.data.sa_workorderid,
  204. }
  205. if (res.code !== 1) return uni.showToast({ title: res.msg, icon: 'none' });
  206. try {
  207. res.data.itemsText = res.data.titems.map(item => {
  208. return `${item.itemname} ${item.model}`;
  209. })
  210. } catch (error) {
  211. }
  212. if (res.data.status == '进行中' && detail.servicetype == '') transition.value = false;
  213. time.value = new Date().getTime()
  214. detail = reactive(res.data);
  215. current.value = steps.findIndex(item => item.value === res.data.status);
  216. })
  217. }
  218. // 提交工单
  219. function submit() {
  220. // 收集所有必填末级节点
  221. const requiredLeafNodes = [];
  222. // 递归查找末级节点
  223. function findLeafNodes(nodeList) {
  224. for (const node of nodeList) {
  225. // 检查是否为末级节点(没有子节点)
  226. if (!node.child || node.child.length === 0) {
  227. // 检查是否是必填节点(required == 11)
  228. if (node.workpresetjson?.required == 11 && node.status !== "1") {
  229. requiredLeafNodes.push(node);
  230. }
  231. } else {
  232. // 递归检查子节点
  233. findLeafNodes(node.child);
  234. }
  235. }
  236. }
  237. // 开始查找
  238. findLeafNodes(detail.nodes);
  239. // 检查所有必填末级节点是否已完成
  240. const allCompleted = requiredLeafNodes.every(node => node.status === "1");
  241. if (allCompleted) {
  242. uni.showModal({
  243. confirmText: '继续提交',
  244. content: '请确认工单内容,提交后不可修改!',
  245. success: ({ confirm }) => {
  246. if (confirm) {
  247. $Http.basic({
  248. id: 2025072315401603,
  249. "content": {
  250. "sa_workorderid": detail.sa_workorderid
  251. }
  252. }).then(res => {
  253. console.log("提交结果", res)
  254. uni.showToast({
  255. title: res.code == 1 ? '提交成功' : res.msg,
  256. icon: 'none'
  257. });
  258. if (res.code == 1) getDetail();
  259. })
  260. }
  261. },
  262. })
  263. } else {
  264. uni.showModal({
  265. confirmText: '关闭',
  266. content: '还有工序未完成,不能提交!',
  267. showCancel: false
  268. })
  269. }
  270. }
  271. // 接单
  272. const takeOrderShow = ref(false);
  273. function takeOrders() {
  274. $Http.basic({
  275. id: 20230210101103,
  276. "content": {
  277. "sa_workorderid": detail.sa_workorderid
  278. }
  279. }).then(res => {
  280. console.log("接单结果", res)
  281. if (res.code == 1) {
  282. takeOrderShow.value = false;
  283. getDetail();
  284. uni.showToast({
  285. title: '接单成功',
  286. icon: 'none'
  287. });
  288. } else {
  289. if (res.msg) uni.showToast({
  290. title: res.msg,
  291. icon: 'none'
  292. });
  293. }
  294. })
  295. }
  296. function toCMTips() {
  297. uni.showModal({
  298. confirmText: '前去修改',
  299. content: '请完善产品信息和客户信息,确认开始后将不可修改!',
  300. success: ({ confirm }) => {
  301. if (confirm) toChangeMsg();
  302. },
  303. })
  304. }
  305. // 修改信息
  306. function toChangeMsg() {
  307. uni.navigateTo({
  308. url: `/pages/workOrder/changeMsg?id=` + sa_workorderid
  309. });
  310. };
  311. // 确认开始
  312. const confirmStartShow = ref(false);
  313. function confirmStart() {
  314. $Http.basic({
  315. id: 20230209144503,
  316. "content": {
  317. "sa_workorderid": detail.sa_workorderid
  318. }
  319. }).then(res => {
  320. console.log("确认开始", res)
  321. if (res.code == 1) {
  322. confirmStartShow.value = false;
  323. getDetail();
  324. uni.showToast({
  325. title: '确认开始成功',
  326. icon: 'none'
  327. });
  328. } else {
  329. if (res.msg) uni.showToast({
  330. title: res.msg,
  331. icon: 'none'
  332. });
  333. }
  334. })
  335. }
  336. defineExpose({ detail })
  337. </script>
  338. <style lang="scss" scoped>
  339. .main {
  340. position: relative;
  341. width: 690rpx;
  342. background: #FFFFFF;
  343. box-shadow: 0rpx 4rpx 16rpx 2rpx rgba(150, 157, 165, 0.16);
  344. border-radius: 10rpx;
  345. box-sizing: border-box;
  346. padding: 40rpx;
  347. margin: 40rpx auto 0;
  348. overflow: hidden;
  349. .changeTransition {
  350. display: flex;
  351. align-items: center;
  352. justify-content: center;
  353. color: #3874F6;
  354. font-size: 28rpx;
  355. position: absolute;
  356. bottom: 0;
  357. left: 0;
  358. width: 100%;
  359. height: 60rpx;
  360. background: #EDF4FF;
  361. .icon-dianjizhankai {
  362. font-size: 20rpx;
  363. margin-left: 16rpx;
  364. transform: rotate(-90deg);
  365. transition: transform 0.3s ease;
  366. }
  367. .shrink {
  368. transform: rotate(90deg);
  369. }
  370. }
  371. .row {
  372. display: flex;
  373. font-size: 28rpx;
  374. font-family: Microsoft YaHei, Microsoft YaHei;
  375. line-height: 32rpx;
  376. margin-top: 20rpx;
  377. .label {
  378. position: relative;
  379. width: 108rpx;
  380. color: #999999;
  381. box-sizing: border-box;
  382. flex-shrink: 0;
  383. margin-right: 30rpx;
  384. }
  385. .label::after {
  386. position: absolute;
  387. top: 0;
  388. right: -12rpx;
  389. content: ':';
  390. }
  391. .value {
  392. color: #333333;
  393. }
  394. .phonenumber {
  395. width: 100%;
  396. display: flex;
  397. align-items: center;
  398. }
  399. .servicetype {
  400. border-radius: 8rpx;
  401. padding: 8rpx 16rpx;
  402. font-weight: bold;
  403. color: #fff;
  404. }
  405. }
  406. .col-center {
  407. display: flex;
  408. align-items: center;
  409. }
  410. .col-center::after {
  411. top: 50% !important;
  412. transform: translateY(-50%);
  413. }
  414. .justify {
  415. text-align: justify;
  416. text-align-last: justify;
  417. }
  418. .billno {
  419. position: relative;
  420. width: 400rpx;
  421. top: -40rpx;
  422. left: -40rpx;
  423. background: #3874F6;
  424. border-radius: 0 0rpx 24rpx 0rpx;
  425. padding: 10rpx 52rpx 10rpx 20rpx;
  426. font-family: Microsoft YaHei, Microsoft YaHei;
  427. font-size: 26rpx;
  428. color: #FFFFFF;
  429. }
  430. }
  431. .but-box {
  432. display: flex;
  433. align-items: center;
  434. justify-content: space-around;
  435. margin-top: 40rpx;
  436. .but-box-item {
  437. width: 45%;
  438. }
  439. }
  440. </style>