taskDetail.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <template>
  2. <view class="page_body">
  3. <!-- 头部 -->
  4. <nav-bar height="96" title="任务详情" :onlyTitle="true" :showHeaderborder="true" @GoBack="GoBack"></nav-bar>
  5. <view class="page_content padding_btm">
  6. <view class="task_title">{{state?.details?.taskName}}</view>
  7. <view class="task_class_collect">
  8. <text class="class_item">{{state?.details?.departmentName}}</text>
  9. <text class="class_item">{{state?.details?.materialCategoryName}}</text>
  10. <text class="class_item">{{state?.details?.createdBy}}</text>
  11. </view>
  12. <view class="task_time">
  13. <view class="time_day">
  14. <text class="time_item">{{state?.details?.startTime}}</text>
  15. <text class="time_item">至</text>
  16. <text class="time_item">{{state?.details?.endTime}}</text>
  17. <text class="time_item" v-if="state?.details?.taskStatus === 1 && remainingDays(state?.details?.endTime) > 0">剩余{{remainingDays(state?.details?.endTime)}}天</text>
  18. </view>
  19. <view :class="['task_status', statusClassMap[state?.details?.taskStatus]]">
  20. {{taskStatusMap[state?.details?.taskStatus]}}
  21. </view>
  22. </view>
  23. <view :class="['task_desc',{'over':!state.isExpand}]">
  24. 采集要求:{{state?.details?.collectionRequire}}
  25. </view>
  26. <view class="task_desc_all">
  27. 采集要求:{{state?.details?.collectionRequire}}
  28. </view>
  29. <view class="expand_btn" v-if="state.showExpandBtn" @click="toggleExpand"><text
  30. class="expand_text">{{!state.isExpand?'展开':'收起'}}</text><uni-icons class="expand_icon"
  31. :type="!state.isExpand?'down':'up'"></uni-icons></view>
  32. </view>
  33. <!-- 间隔 -->
  34. <view class="row_gap"></view>
  35. <view class="page_content">
  36. <view class="total">
  37. <view class="status_tag" :class="state.auditStatus">
  38. <text>{{ tabStatusClassMap[state.auditStatus] }}:{{ state?.details?.taskTargetNum }}</text>
  39. </view>
  40. </view>
  41. <template v-for="item in (state?.details?.taskTargetVos || [])">
  42. <view class="list_item" v-if="item.isShow!==1" :Key="item.id">
  43. <view class="item_name_file">
  44. <view class="name_file">
  45. <text class="name">{{item.targetName}}</text>
  46. <text class="file_num">文件数量:{{item?.fileNum || 0}}</text>
  47. </view>
  48. <view class="btn" @click="HandleDetail(item.id)">{{state.auditStatus == 'notSubmitList'?'立即提交':'查看'}}</view>
  49. </view>
  50. <view class="item_info">
  51. <template v-for="text in ['departmentName','departmentGroupName','subjectName','gradeName','classTypeName','className','updateTime']">
  52. <text class="info_text" v-if="item?.[text]" :key="text">{{item?.[text]}}</text>
  53. </template>
  54. </view>
  55. </view>
  56. </template>
  57. </view>
  58. </view>
  59. </template>
  60. <script setup>
  61. import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
  62. import navBar from '@/components/navBar.vue';
  63. import { remainingDays } from '@/common/common.js';
  64. import {onLoad,onShow} from '@dcloudio/uni-app';
  65. import {
  66. reactive,
  67. ref,
  68. nextTick,
  69. getCurrentInstance,
  70. onMounted,
  71. onUnmounted
  72. } from 'vue';
  73. const state = reactive({
  74. taskId: '', //任务id
  75. auditStatus:'',//审核状态
  76. showExpandBtn: false, //是否显示展开按钮
  77. isExpand: false, //是否展开
  78. details: {}, //详情信息
  79. });
  80. const statusClassMap = {
  81. 1: 'status_published',
  82. 2: 'status_closed'
  83. };
  84. const taskStatusMap = {
  85. 1: '进行中',
  86. 2: '已结束'
  87. };
  88. const tabStatusClassMap = {
  89. 'notSubmitList':'待提交',// 待提交
  90. 'notReviewList':'审核中',// 审核中
  91. 'reviewReasonList':'已驳回',// 已驳回
  92. 'reviewList':'已提交'// 已提交
  93. };
  94. onShow(()=>{
  95. const isLoadSubmitMaterialTaskDetail = uni.getStorageSync('isLoadSubmitMaterialTaskDetail');
  96. if(isLoadSubmitMaterialTaskDetail){
  97. OnLoadData();
  98. }
  99. })
  100. onUnmounted(()=>{
  101. uni.removeStorageSync('isLoadSubmitMaterialTaskDetail');
  102. })
  103. onLoad((option) => {
  104. state.taskId = option.taskId;
  105. state.auditStatus = option.auditStatus;
  106. })
  107. onMounted(() => {
  108. OnLoadData();
  109. checkTextOverflow();
  110. });
  111. const OnLoadData = () => {
  112. state.details = uni.getStorageSync('submitMaterialDetailInfo') || {};
  113. const taskTargetData = state?.details?.taskTargetVos || [];
  114. state.details.taskTargetNum = taskTargetData.filter(item=>item.isShow!=1)?.length;
  115. }
  116. const checkTextOverflow = () => {
  117. nextTick(() => {
  118. const instance = getCurrentInstance();
  119. // 安全保护
  120. if (!instance || !instance.proxy) {
  121. // 备用方案:全局查询(要求元素 class 唯一)
  122. let taskDescAllHeight = 0,
  123. taskDescHeight = 0;
  124. const query = uni.createSelectorQuery();
  125. query.select('.task_desc_all').boundingClientRect((rect) => {
  126. taskDescAllHeight = rect?.height || 0;
  127. });
  128. query.select('.task_desc').boundingClientRect((rect) => {
  129. taskDescHeight = rect?.height || 0;
  130. });
  131. query.select('.page_content_data').boundingClientRect((rect) => {
  132. state.searchBoxTop = rect?.top || 0;
  133. });
  134. query.exec(() => {
  135. // 所有回调执行完毕后触发
  136. state.showExpandBtn = taskDescAllHeight > taskDescHeight + 1;
  137. });
  138. return;
  139. }
  140. let taskDescAllHeight = 0,
  141. taskDescHeight = 0;
  142. const query = uni.createSelectorQuery().in(instance.proxy);
  143. query.select('.task_desc_all').boundingClientRect((rect) => {
  144. taskDescAllHeight = rect?.height || 0;
  145. });
  146. query.select('.task_desc').boundingClientRect((rect) => {
  147. taskDescHeight = rect?.height || 0;
  148. });
  149. query.select('.page_content_data').boundingClientRect((rect) => {
  150. state.searchBoxTop = rect?.top || 0;
  151. });
  152. query.exec(() => {
  153. // 所有回调执行完毕后触发
  154. state.showExpandBtn = taskDescAllHeight > taskDescHeight + 1;
  155. });
  156. });
  157. }
  158. // 展开收起切换
  159. const toggleExpand = () => {
  160. state.isExpand = !state.isExpand;
  161. }
  162. //提交材料
  163. const HandleDetail = (targetId) => {
  164. let auditStatus = '';
  165. if(state.auditStatus == 'notSubmitList'){
  166. auditStatus = '1';
  167. }else if(state.auditStatus == 'notReviewList'){
  168. auditStatus = '2';
  169. }else if(state.auditStatus == 'reviewReasonList'){
  170. auditStatus = '3';
  171. }else if(state.auditStatus == 'reviewList'){
  172. auditStatus = '4';
  173. }else{
  174. auditStatus = '';
  175. }
  176. uni.navigateTo({
  177. url: `/pages/materialCollection/submitMaterial/submitDetail?taskId=${state.taskId}&targetId=${targetId}&auditStatus=${auditStatus}`
  178. });
  179. }
  180. //返回
  181. const GoBack = () => {
  182. uni.navigateBack({
  183. delta: 1
  184. });
  185. }
  186. </script>
  187. <style scoped lang="scss">
  188. .page_content {
  189. &.padding_btm {
  190. padding-bottom: 24rpx;
  191. .task_title {
  192. font-weight: 500;
  193. font-size: 32rpx;
  194. color: #333333;
  195. margin-top: 24rpx;
  196. }
  197. .task_class_collect {
  198. display: inline-flex;
  199. align-items: center;
  200. flex-wrap: wrap;
  201. width: 100%;
  202. margin-top: 16rpx;
  203. gap: 16rpx;
  204. .class_item {
  205. font-weight: 400;
  206. font-size: 24rpx;
  207. color: #999999;
  208. }
  209. }
  210. .task_time {
  211. display: flex;
  212. align-items: flex-start;
  213. width: 100%;
  214. margin-top: 16rpx;
  215. .time_day {
  216. display: inline-flex;
  217. align-items: center;
  218. flex-wrap: wrap;
  219. flex: 1;
  220. .time_item {
  221. font-weight: 400;
  222. font-size: 24rpx;
  223. line-height: 48rpx;
  224. color: #999999;
  225. &:nth-child(2) {
  226. margin: 0 8rpx;
  227. }
  228. &:nth-child(4) {
  229. color: #2E64FA;
  230. margin-left: 16rpx;
  231. }
  232. }
  233. }
  234. .task_status {
  235. display: inline-flex;
  236. align-items: center;
  237. height: 48rpx;
  238. padding: 0 12rpx;
  239. border-radius: 8rpx;
  240. font-weight: 400;
  241. font-size: 24rpx;
  242. &.status_pending {
  243. background: rgba(46, 100, 250, 0.1);
  244. color: #2E64FA;
  245. }
  246. &.status_published {
  247. background: rgba(82, 196, 26, 0.1);
  248. color: #2BC644;
  249. }
  250. &.status_closed {
  251. background: #6666661a;
  252. color: #666666;
  253. }
  254. }
  255. }
  256. .task_desc {
  257. margin-top: 24rpx;
  258. display: flex;
  259. width: 100%;
  260. padding-top: 24rpx;
  261. border-top: 2rpx solid #F3F3F3;
  262. font-weight: 400;
  263. font-size: 28rpx;
  264. color: #999999;
  265. line-height: 44rpx;
  266. box-sizing: border-box;
  267. position: relative;
  268. &.over {
  269. max-height: 168rpx;
  270. overflow: hidden;
  271. transition: all 0.25s;
  272. display: -webkit-box;
  273. -webkit-line-clamp: 3;
  274. -webkit-box-orient: vertical;
  275. }
  276. }
  277. .task_desc_all {
  278. display: flex;
  279. width: 100%;
  280. padding-top: 24rpx;
  281. border-top: 2rpx solid #F3F3F3;
  282. font-weight: 400;
  283. font-size: 28rpx;
  284. color: #999999;
  285. line-height: 44rpx;
  286. box-sizing: border-box;
  287. position: absolute;
  288. left: -9999px;
  289. top: 0;
  290. visibility: hidden; // 不可见但占据空间(不影响布局,因为absolute)
  291. pointer-events: none;
  292. }
  293. .expand_btn {
  294. width: 100%;
  295. height: 40rpx;
  296. background-color: #FFFFFF;
  297. display: flex;
  298. justify-content: flex-end;
  299. align-items: center;
  300. .expand_text {
  301. font-weight: 400;
  302. font-size: 28rpx;
  303. color: #2E64FA;
  304. margin-right: 8rpx;
  305. }
  306. .expand_icon {
  307. font-size: 32rpx !important;
  308. color: #2E64FA !important;
  309. }
  310. }
  311. }
  312. }
  313. .row_gap {
  314. background-color: #F8F9FD;
  315. width: 100%;
  316. height: 24rpx;
  317. }
  318. .total {
  319. width: 100%;
  320. display: flex;
  321. padding: 24rpx 0;
  322. border-bottom: 2rpx solid #F3F3F3;
  323. .status_tag{
  324. font-size: 24rpx;
  325. text-align: center;
  326. padding: 8rpx 12rpx;
  327. font-weight: 400;
  328. border-radius: 8rpx;
  329. flex-shrink: 0;
  330. &.notSubmitList {
  331. background: rgba(46,100,250,0.1);
  332. color: #2E64FA;
  333. }
  334. &.notReviewList {
  335. background: rgba(251,159,52,0.1);
  336. color: #FB9F34;
  337. }
  338. &.reviewReasonList {
  339. background: rgba(245,108,108,0.1);
  340. color: #F56C6C;
  341. }
  342. &.reviewList {
  343. background: rgba(43,198,68,0.1);
  344. color: #2BC644;
  345. }
  346. }
  347. }
  348. .list_item {
  349. display: flex;
  350. flex-direction: column;
  351. width: 100%;
  352. padding: 24rpx 0;
  353. border-bottom: 2rpx solid #F3F3F3;
  354. .item_name_file{
  355. display: flex;
  356. width: 100%;
  357. align-items: center;
  358. gap: 20rpx;
  359. .name_file{
  360. flex:1;
  361. gap: 20rpx;
  362. display: flex;
  363. align-items: center;
  364. .name{
  365. font-weight: 500;
  366. font-size: 32rpx;
  367. color: #333333;
  368. }
  369. .file_num{
  370. font-weight: 400;
  371. font-size: 24rpx;
  372. color: #2E64FA;
  373. }
  374. }
  375. .btn{
  376. padding: 12rpx 24rpx;
  377. border-radius: 8rpx;
  378. border: 2rpx solid #2E64FA;
  379. font-weight: 400;
  380. font-size: 28rpx;
  381. color: #2E64FA;
  382. display: inline-flex;
  383. align-items: center;
  384. justify-content: center;
  385. }
  386. }
  387. .item_info{
  388. margin-top: 16rpx;
  389. display: flex;
  390. gap: 16rpx;
  391. align-items: center;
  392. flex-wrap: wrap;
  393. .info_text{
  394. font-weight: 400;
  395. font-size: 24rpx;
  396. color: #999999;
  397. flex-shrink: 0;
  398. }
  399. }
  400. }
  401. </style>