index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. <route lang="yaml">
  2. style:
  3. navigationBarTitleText: 任务详情
  4. navigationBarBackgroundColor: '#fff'
  5. </route>
  6. <script lang="ts" setup>
  7. import Card from '@designer-hub/app/src/components/card.vue'
  8. import SectionHeading from '@designer-hub/app/src/components/section-heading.vue'
  9. import BottomAppBar from '@/components/bottom-app-bar.vue'
  10. import DataForm from '@/components/data-form.vue'
  11. import { appTaskReport, getTaskDetail, taskReceive } from '../../../../core/libs/requests'
  12. import { useUserStore } from '../../../../store'
  13. import { storeToRefs } from 'pinia'
  14. import dayjs from 'dayjs'
  15. import { DataFormSchema } from '../../../../components/data-form'
  16. import { ComponentExposed } from 'vue-component-type-helpers'
  17. import { useTask } from '../../../../composables/task'
  18. import { requestToast } from '@designer-hub/app/src/core/utils/common'
  19. const { getBgClass, getColor, getTypeTitle, getBgStyle } = useTask()
  20. const taskId = ref()
  21. const publishState = ref(false)
  22. const formData = ref<any>({})
  23. const userStore = useUserStore()
  24. const { userInfo } = storeToRefs(userStore)
  25. const { data: taskDetails, run: setTaskDetails } = useRequest(() =>
  26. getTaskDetail({ brokerId: userInfo.value.userId, taskId: taskId.value }),
  27. )
  28. const dataFormRef = ref<ComponentExposed<typeof DataForm>>()
  29. const customerSchema = ref<DataFormSchema>({
  30. num: {
  31. type: 'TextField',
  32. label: '个人完成量:',
  33. required: true,
  34. props: {
  35. placeholder: '请输入个人完成量',
  36. },
  37. },
  38. remark: {
  39. type: 'Textarea',
  40. label: '上报说明:',
  41. required: true,
  42. props: {
  43. placeholder: '请输入上报说明',
  44. },
  45. },
  46. })
  47. const customerRules = ref({
  48. num: [{ required: true, message: '请输入个人完成量', trigger: 'blur' }],
  49. remark: [{ required: true, message: '请输入上报说明', trigger: 'blur' }],
  50. })
  51. const initData = async () => {
  52. await setTaskDetails()
  53. }
  54. const submitTask = async () => {
  55. await uni.showLoading()
  56. const { valid } = await dataFormRef.value!.validate()
  57. if (!valid) {
  58. uni.hideLoading()
  59. return
  60. }
  61. console.log(formData.value)
  62. await requestToast(
  63. () =>
  64. appTaskReport({
  65. brokerId: userInfo.value.userId,
  66. taskId: taskId.value,
  67. ...formData.value,
  68. }),
  69. { success: true, successTitle: '上报成功' },
  70. )
  71. uni.hideLoading()
  72. await setTaskDetails()
  73. publishState.value = false
  74. }
  75. const acceptingOrders = async () => {
  76. await uni.showLoading()
  77. const res = await taskReceive({
  78. brokerId: userInfo.value.userId,
  79. taskId: taskDetails.value.id,
  80. orders: true,
  81. })
  82. uni.hideLoading()
  83. await initData()
  84. }
  85. const acceptingNoOrders = async () => {
  86. await uni.showLoading()
  87. const res = await taskReceive({
  88. brokerId: userInfo.value.userId,
  89. taskId: taskDetails.value.id,
  90. orders: false,
  91. })
  92. uni.hideLoading()
  93. await initData()
  94. }
  95. onLoad(async (query?: Record<string | 'taskId', string>) => {
  96. taskId.value = query?.taskId
  97. await initData()
  98. })
  99. </script>
  100. <template>
  101. <view class="flex-grow flex flex-col p-4 gap-4" style="position: relative">
  102. <Card
  103. :custom-class="`px-0 py-0`"
  104. :custom-style="`${taskDetails && getBgStyle(Number(taskDetails.taskType))}`"
  105. >
  106. <div class="flex items-center py-[20px] px-[15px]">
  107. <div class="text-black/90 text-lg font-normal font-['PingFang_SC'] leading-none">
  108. {{ taskDetails && getTypeTitle(Number(taskDetails.taskType)) }}
  109. </div>
  110. <div class="flex-1"></div>
  111. <div
  112. class="w-[47px] h-[23px] px-1 rounded border justify-center items-center gap-2.5 inline-flex"
  113. :style="{ backgroundColor: getColor(Number(taskDetails?.taskType)) }"
  114. >
  115. <div class="text-right text-white text-xs font-normal font-['PingFang_SC'] leading-tight">
  116. {{ taskDetails?.statusName }}
  117. </div>
  118. </div>
  119. </div>
  120. <div class="bg-[#f6f7ff] rounded-t-2 p-5 flex flex-col gap-4">
  121. <div class="flex flex-row items-center justify-start gap-2">
  122. <div style="width: 50px; height: 50px">
  123. <wd-circle
  124. :model-value="
  125. ((taskDetails?.completedNum ?? 0) / (taskDetails?.storeQuantity ?? 0)) * 100
  126. "
  127. :size="50"
  128. :color="getColor(Number(taskDetails?.taskType))"
  129. :clockwise="false"
  130. >
  131. <div class="flex flex-col items-center">
  132. <div class="w-[29.20px] h-[18.39px] text-black text-sm font-medium font-['DIN']">
  133. {{
  134. ((taskDetails?.completedNum ?? 0) / (taskDetails?.storeQuantity ?? 0)) * 100
  135. }}%
  136. </div>
  137. <div
  138. class="w-[22.71px] h-[10.82px] text-black/60 text-[7px] font-normal font-['PingFang_SC']"
  139. >
  140. 达成率
  141. </div>
  142. </div>
  143. </wd-circle>
  144. </div>
  145. <div class="flex flex-row items-center justify-start ml-[37px]">
  146. <div class="text-black/60 text-sm font-normal font-['PingFang_SC']">奖励积分:</div>
  147. <div class="flex items-end gap-1">
  148. <div class="text-[#ff2d2d] text-[22px] font-medium font-['DIN'] leading-22px">
  149. {{ taskDetails?.pointsReward }}
  150. </div>
  151. <div class="text-[#ff2d2d] text-xs font-normal font-['PingFang_SC']">积分</div>
  152. </div>
  153. </div>
  154. </div>
  155. <div class="flex flex-row items-center justify-between gap-2">
  156. <div class="flex items-center justify-center flex-col">
  157. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">目标</div>
  158. <div class="text-black/90 text-lg font-medium font-['DIN'] leading-normal">
  159. {{ taskDetails?.storeQuantity }}
  160. </div>
  161. </div>
  162. <div style="width: 1px; height: 10px; background: #e8e8e8"></div>
  163. <div class="flex items-center justify-center flex-col">
  164. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">个人完成</div>
  165. <div class="text-black/90 text-lg font-medium font-['DIN'] leading-normal">
  166. {{ taskDetails?.personalCompletedNum }}
  167. </div>
  168. </div>
  169. <div style="width: 1px; height: 5px; background: #e8e8e8"></div>
  170. <div class="flex items-center justify-center flex-col">
  171. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">累计完成</div>
  172. <div class="text-black/90 text-lg font-medium font-['DIN'] leading-normal">
  173. {{ taskDetails?.completedNum ?? 0 }}
  174. </div>
  175. </div>
  176. <!-- </div>-->
  177. </div>
  178. </div>
  179. <div class="bg-[#ffffff] p-[14px] pt-[24px]">
  180. <div class="mb-[19px]">
  181. <span class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  182. 任务名称:
  183. </span>
  184. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
  185. {{ taskDetails?.name }}
  186. </span>
  187. </div>
  188. <div class="mb-[19px]">
  189. <span class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  190. 发起方:
  191. </span>
  192. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
  193. {{ taskDetails?.bearerName }}
  194. </span>
  195. </div>
  196. <div class="mb-[19px]">
  197. <span class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  198. 适用店面:
  199. </span>
  200. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
  201. {{ taskDetails?.shopNames }}
  202. </span>
  203. </div>
  204. <div class="mb-[19px]">
  205. <span class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  206. 任务时间:
  207. </span>
  208. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
  209. {{ dayjs(taskDetails?.startTime).format('YYYY/MM/DD') }}-{{
  210. dayjs(taskDetails?.endTime).format('YYYY/MM/DD')
  211. }}
  212. </span>
  213. </div>
  214. <div class="mb-[19px]">
  215. <span class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  216. 详细说明:
  217. </span>
  218. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
  219. {{ taskDetails?.detail }}
  220. </span>
  221. </div>
  222. <div>
  223. <span class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  224. 完成方式:
  225. </span>
  226. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none">
  227. {{ taskDetails?.finalTypeName }}
  228. </span>
  229. </div>
  230. </div>
  231. <div class="bg-[#ffffff] p-[14px]">
  232. <div class="flex items-center justify-between">
  233. <div class="text-black/90 text-sm font-normal font-['PingFang_SC'] leading-none">
  234. 已接单经纪人
  235. </div>
  236. <div class="text-black/40 text-sm font-normal font-['PingFang_SC'] leading-none">
  237. {{ taskDetails?.brokerList.length }}
  238. </div>
  239. </div>
  240. <div class="flex items-center justify-start gap-3">
  241. <template v-for="item in taskDetails?.brokerList" :key="item.id">
  242. <div class="my-[23px]">
  243. <img class="w-[46px] h-[46px] rounded-full" :src="item.headImgUrl" alt="" />
  244. <div
  245. class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-none mt-[10px]"
  246. >
  247. {{ item.brokerName }}
  248. </div>
  249. </div>
  250. </template>
  251. </div>
  252. </div>
  253. </Card>
  254. <Card>
  255. <div class="flex items-center">
  256. <div class="mr-2.5 w-1 h-4 rotate-180 bg-[#2357e9] rounded-[20px]"></div>
  257. <SectionHeading title="数据明细" size="base"></SectionHeading>
  258. </div>
  259. <!-- 到店打卡-->
  260. <div v-if="taskDetails?.finalType == '1'" class="flex flex-col gap-4 mt-5">
  261. <!-- <template v-for="item in taskDetails?.brokerList" :key="item.id">-->
  262. <!-- <div class="flex gap-2.5 p-3.5 bg-[#f7fbff] items-center rounded-[10px]">-->
  263. <!-- <wd-img width="44" height="44" round :src="item.headImgUrl" />-->
  264. <!-- <div class="flex-1 flex flex-col gap-2">-->
  265. <!-- <div class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal">-->
  266. <!-- {{ item.brokerName }}-->
  267. <!-- </div>-->
  268. <!-- <div class="text-black/30 text-sm font-normal font-['PingFang_SC'] leading-none">-->
  269. <!-- {{ item.finalTypeName }}{{ item.shopNames }}-->
  270. <!-- </div>-->
  271. <!-- </div>-->
  272. <!-- <div class="h-full flex items-start">-->
  273. <!-- <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal">-->
  274. <!-- {{ dayjs(item.createTime).format('YYYY/MM/DD HH:mm') }}-->
  275. <!-- </div>-->
  276. <!-- </div>-->
  277. <!-- </div>-->
  278. <!-- </template>-->
  279. </div>
  280. <!-- 上报-->
  281. <div v-else>
  282. <template v-for="(item, i) in taskDetails?.reportList" :key="i">
  283. <div class="bg-[#f7fbff] rounded-[10px] py-[22px] px-[16px] mt-[20px]">
  284. <div class="flex items-center justify-between">
  285. <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal">
  286. {{ dayjs(item.createTime).format('YYYY/MM/DD HH:mm') }}
  287. </div>
  288. <div
  289. class="text-xs font-normal font-['PingFang_SC'] leading-normal"
  290. :class="
  291. { '0': 'text-[#16b032]', '1': 'text-[#2357e9]', '2': 'text-#ff2d2d' }[
  292. String(item.status)
  293. ]
  294. "
  295. >
  296. {{
  297. String(item.status) === '0'
  298. ? '审核通过'
  299. : String(item.status) === '1'
  300. ? '审核中'
  301. : '驳回'
  302. }}
  303. </div>
  304. </div>
  305. <div class="mt-[7px]">
  306. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal">
  307. 个人完成量:
  308. </span>
  309. <span class="text-black/90 text-sm font-normal font-['PingFang_SC'] leading-normal">
  310. {{ item.num }}
  311. </span>
  312. </div>
  313. <div class="mt-[2px]">
  314. <span class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal">
  315. 上报说明
  316. </span>
  317. <span class="text-black/90 text-sm font-normal font-['PingFang_SC'] leading-normal">
  318. </span>
  319. <span class="text-black/90 text-sm font-normal font-['PingFang_SC'] leading-normal">
  320. {{ item.remark }}
  321. </span>
  322. </div>
  323. <template v-if="String(item.status) === '2'">
  324. <div class="bg-[#e6e8f1] my-4 border-[0.5px] border-solid border-[#e6e8f1]"></div>
  325. <div class="text-[#ff2d2d] text-xs font-normal font-['PingFang_SC'] leading-none">
  326. 原因:{{ item.reason }}
  327. </div>
  328. </template>
  329. </div>
  330. </template>
  331. </div>
  332. </Card>
  333. <template v-if="taskDetails?.receive">
  334. <BottomAppBar fixed placeholder>
  335. <div class="flex items-center justify-between gap-3">
  336. <div
  337. @click="acceptingNoOrders"
  338. class="grow shrink basis-0 px-5 py-3 bg-[#f2f3ff] rounded-md justify-center items-center gap-1 flex"
  339. >
  340. <div
  341. class="text-center text-[#ff2d2d] text-base font-normal font-['PingFang_SC'] leading-normal"
  342. >
  343. 不接单
  344. </div>
  345. </div>
  346. <div
  347. @click="acceptingOrders"
  348. class="grow shrink basis-0 px-5 py-3 bg-[#2357e9] rounded-md justify-center items-center gap-1 flex"
  349. >
  350. <div
  351. class="text-center text-white text-base font-normal font-['PingFang_SC'] leading-normal"
  352. >
  353. 接单
  354. </div>
  355. </div>
  356. </div>
  357. </BottomAppBar>
  358. </template>
  359. <template v-if="!taskDetails?.receive && String(taskDetails?.finalType) === '2'">
  360. <BottomAppBar fixed placeholder>
  361. <div class="px-5 py-3 bg-[#2357e9] rounded-md justify-center items-center gap-1">
  362. <div
  363. @click="publishState = true"
  364. class="text-center text-white text-base font-normal font-['PingFang_SC'] leading-normal"
  365. >
  366. 上报
  367. </div>
  368. </div>
  369. </BottomAppBar>
  370. </template>
  371. <wd-action-sheet v-model="publishState" title="" @close="publishState = false">
  372. <view class="flex flex-col p-4 mt-4">
  373. <DataForm
  374. ref="dataFormRef"
  375. :schema="customerSchema"
  376. :rules="customerRules"
  377. v-model="formData"
  378. ></DataForm>
  379. <div><wd-button block :round="false" @click="submitTask">提交</wd-button></div>
  380. </view>
  381. </wd-action-sheet>
  382. </view>
  383. </template>