submitDetail.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  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_height">
  6. <view class="page_content padding_btm">
  7. <view class="task_title">{{state?.details?.taskName}}</view>
  8. <view class="task_class_collect">
  9. <text class="class_item">{{state?.details?.departmentName}}</text>
  10. <text class="class_item">{{state?.details?.materialCategoryName}}</text>
  11. <text class="class_item">{{state?.details?.createdBy}}</text>
  12. </view>
  13. <view class="task_time">
  14. <view class="time_day">
  15. <text class="time_item">{{state?.details?.startTime}}</text>
  16. <text class="time_item">至</text>
  17. <text class="time_item">{{state?.details?.endTime}}</text>
  18. <text class="time_item" v-if="state?.details?.taskStatus === 1 && remainingDays(state?.details?.endTime) > 0">剩余{{remainingDays(state?.details?.endTime)}}天</text>
  19. </view>
  20. <view :class="['task_status', statusClassMap[state?.details?.taskStatus]]">
  21. {{taskStatusMap[state?.details?.taskStatus]}}
  22. </view>
  23. </view>
  24. <view :class="['task_desc',{'over':!state.isExpand}]">
  25. 采集要求:{{state?.details?.collectionRequire}}
  26. </view>
  27. <view class="task_desc_all">
  28. 采集要求:{{state?.details?.collectionRequire}}
  29. </view>
  30. <view class="expand_btn" v-if="state.showExpandBtn" @click="toggleExpand"><text
  31. class="expand_text">{{!state.isExpand?'展开':'收起'}}</text><uni-icons class="expand_icon"
  32. :type="!state.isExpand?'down':'up'"></uni-icons></view>
  33. </view>
  34. <!-- 间隔 -->
  35. <view class="row_gap"></view>
  36. <view class="page_content">
  37. <view class="target_status">
  38. <view class="target_tag">
  39. <template v-for="text in ['departmentName','departmentGroupName','subjectName','gradeName','classTypeName','className']">
  40. <text class="info_text" v-if="state?.targetFileList?.[text]" :key="text">{{state?.targetFileList?.[text]}}</text>
  41. </template>
  42. </view>
  43. <template v-if="state?.details?.auditMechanism === 1">
  44. <view v-if="state?.targetFileList?.targetStatus=== 1" class="status_tag notSubmitList">
  45. <text>待提交</text>
  46. </view>
  47. <view v-if="state?.targetFileList?.targetStatus=== 3" class="status_tag reviewReasonList">
  48. <text>已驳回</text>
  49. </view>
  50. <view v-if="state?.targetFileList?.targetStatus=== 2" class="status_tag notReviewList">
  51. <text>审核中</text>
  52. </view>
  53. <view v-if="state?.targetFileList?.targetStatus=== 4" class="status_tag reviewList">
  54. <text>已提交</text>
  55. </view>
  56. </template>
  57. <template v-if="state?.details?.auditMechanism === 0">
  58. <view v-if="state?.targetFileList?.targetStatus=== 1" class="status_tag notSubmitList">
  59. <text>待提交</text>
  60. </view>
  61. <view v-else class="status_tag reviewList">
  62. <text>已提交</text>
  63. </view>
  64. </template>
  65. </view>
  66. <!-- 上传按钮 提交状态 1待提交 2审核中 3已驳回 4已提交 -->
  67. <view class="upload_box">
  68. <template v-if="state?.targetFileList?.targetStatus === 1 && state?.details?.taskStatus !== 2">
  69. <image class="upload_icon" src="@/static/image/icon/upload_icon.png"></image>
  70. <view class="upload_text">
  71. <view class="upload_title">点击上传文件</view>
  72. <view class="upload_desc">支持Word、Excel、PPT、图片(最大100MB)</view>
  73. </view>
  74. </template>
  75. <template v-if="(state?.targetFileList?.targetStatus === 2 || state?.targetFileList?.targetStatus === 4) && state?.details?.taskStatus !== 2">
  76. <image class="upload_icon" src="@/static/image/icon/upload_locked.png"></image>
  77. <view class="upload_text">
  78. <view class="upload_title">点击重新编辑可再提交</view>
  79. <view class="upload_desc">支持Word、Excel、PPT、图片(最大100MB)</view>
  80. </view>
  81. </template>
  82. <template v-if="state?.targetFileList?.targetStatus === 3 && state?.details?.taskStatus !== 2">
  83. <image class="upload_icon" src="@/static/image/icon/upload_locked.png"></image>
  84. <view class="upload_text">
  85. <view class="upload_title">请先删除全部文件,再提交调整后的合规材料</view>
  86. <view class="upload_desc">支持Word、Excel、PPT、图片(最大100MB)</view>
  87. </view>
  88. </template>
  89. <template v-if="state?.details?.taskStatus == 2">
  90. <image class="upload_icon" src="@/static/image/icon/upload_locked.png"></image>
  91. <view class="upload_text">
  92. <view class="upload_title">已结束不可再提交</view>
  93. <view class="upload_desc">支持Word、Excel、PPT、图片(最大100MB)</view>
  94. </view>
  95. </template>
  96. </view>
  97. <view class="list_item" v-for="item in (state?.targetFileList?.taskTargetFileVos || [])" :Key="item.id">
  98. <image class="file_icon" src="@/static/image/icon/file.png"></image>
  99. <view class="file_info">
  100. <view class="file_name">{{item.fileName}}</view>
  101. <view class="file_size">
  102. <text>{{getFileSize(item.fileSize)}}</text>
  103. <text>{{ item.createTime }}</text>
  104. </view>
  105. </view>
  106. <view class="file_btn">
  107. <text @click="HandleDeleteFileList(item)" :class="['del',{'disabled':state?.targetFileList?.targetStatus === 2 || state?.targetFileList?.targetStatus === 4}]">删除</text>
  108. <text class="download">下载</text>
  109. </view>
  110. </view>
  111. </view>
  112. </view>
  113. <view class="page_foot" v-if="state?.details?.taskStatus!=2">
  114. <!-- 提交状态 1待提交 2审核中 3已驳回 4已提交 -->
  115. <template v-if="(state?.targetFileList?.targetStatus === 1 || state?.targetFileList?.targetStatus === 3)">
  116. <view @click="DeleteAllFiles" :class="['del',{'disabled':!state?.targetFileList?.taskTargetFileVos?.length}]">删除全部</view>
  117. <view class="submit" @click="UpdateTaskTarget">提交</view>
  118. </template>
  119. <template v-else>
  120. <view class="del disabled">删除全部</view>
  121. <view class="submit" @click="UpdateTaskTargetReset">重新编辑</view>
  122. </template>
  123. </view>
  124. <!-- 删除确认框 -->
  125. <popupDialog ref="popupDelDialogRef" :showFootBorder="true" :content="state.delDialog.content" @DialogConfirm="DialogDelConfirm" />
  126. </view>
  127. </template>
  128. <script setup>
  129. import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
  130. import popupDialog from '@/components/popupDialog.vue';
  131. import navBar from '@/components/navBar.vue';
  132. import { remainingDays,getFileSize } from '@/common/common.js';
  133. import {getTaskTargetFileList,DeleteFileList,DelTaskTargetFileList,updateTaskTarget} from '@/reqApi/notification.js';
  134. import {onLoad} from '@dcloudio/uni-app';
  135. import {
  136. reactive,
  137. ref,
  138. nextTick,
  139. getCurrentInstance,
  140. onMounted
  141. } from 'vue';
  142. const state = reactive({
  143. taskId: '', //任务id
  144. targetId:'',//
  145. showExpandBtn: false, //是否显示展开按钮
  146. isExpand: false, //是否展开
  147. details: {}, //详情信息
  148. targetFileList:{},
  149. delDialog:{
  150. type:'',
  151. content:'',
  152. fileUrls:[],
  153. targetFileIds:[]
  154. },
  155. });
  156. const popupDelDialogRef = ref(null);
  157. const statusClassMap = {
  158. 1: 'status_published',
  159. 2: 'status_closed'
  160. };
  161. const taskStatusMap = {
  162. 1: '进行中',
  163. 2: '已结束'
  164. };
  165. onLoad((option) => {
  166. state.taskId = option.taskId;
  167. state.targetId = option.targetId;
  168. })
  169. onMounted(() => {
  170. state.details = uni.getStorageSync('submitMaterialDetailInfo') || {};
  171. checkTextOverflow();
  172. GetTaskTargetFileList();
  173. });
  174. const checkTextOverflow = () => {
  175. nextTick(() => {
  176. const instance = getCurrentInstance();
  177. // 安全保护
  178. if (!instance || !instance.proxy) {
  179. // 备用方案:全局查询(要求元素 class 唯一)
  180. let taskDescAllHeight = 0,
  181. taskDescHeight = 0;
  182. const query = uni.createSelectorQuery();
  183. query.select('.task_desc_all').boundingClientRect((rect) => {
  184. taskDescAllHeight = rect?.height || 0;
  185. });
  186. query.select('.task_desc').boundingClientRect((rect) => {
  187. taskDescHeight = rect?.height || 0;
  188. });
  189. query.select('.page_content_data').boundingClientRect((rect) => {
  190. state.searchBoxTop = rect?.top || 0;
  191. });
  192. query.exec(() => {
  193. // 所有回调执行完毕后触发
  194. state.showExpandBtn = taskDescAllHeight > taskDescHeight + 1;
  195. });
  196. return;
  197. }
  198. let taskDescAllHeight = 0,
  199. taskDescHeight = 0;
  200. const query = uni.createSelectorQuery().in(instance.proxy);
  201. query.select('.task_desc_all').boundingClientRect((rect) => {
  202. taskDescAllHeight = rect?.height || 0;
  203. });
  204. query.select('.task_desc').boundingClientRect((rect) => {
  205. taskDescHeight = rect?.height || 0;
  206. });
  207. query.select('.page_content_data').boundingClientRect((rect) => {
  208. state.searchBoxTop = rect?.top || 0;
  209. });
  210. query.exec(() => {
  211. // 所有回调执行完毕后触发
  212. state.showExpandBtn = taskDescAllHeight > taskDescHeight + 1;
  213. });
  214. });
  215. }
  216. // 展开收起切换
  217. const toggleExpand = () => {
  218. state.isExpand = !state.isExpand;
  219. }
  220. //获取当前教师提交的文件列表
  221. const GetTaskTargetFileList = () => {
  222. getTaskTargetFileList(state.targetId).then(res=>{
  223. if(res.code == 200){
  224. state.targetFileList = res.data || {};
  225. }
  226. })
  227. }
  228. //单个删除
  229. const HandleDeleteFileList = (item) => {
  230. if(state?.targetFileList?.targetStatus === 2 || state?.targetFileList?.targetStatus === 4){
  231. return false
  232. }
  233. const { filePath, id } = item;
  234. state.delDialog = {
  235. type:'del',
  236. content:'是否删除当前文件?',
  237. fileUrls:[filePath],
  238. targetFileIds:[id]
  239. };
  240. popupDelDialogRef.value.OpenDialog();
  241. }
  242. //删除全部
  243. const DeleteAllFiles = () => {
  244. let fileUrls = [],targetFileIds = [];
  245. const taskTargetFileVos = state?.targetFileList?.taskTargetFileVos || [];
  246. if(taskTargetFileVos.length > 0){
  247. taskTargetFileVos.forEach(item => {
  248. fileUrls.push(item.filePath);
  249. targetFileIds.push(item.id)
  250. })
  251. state.delDialog = {
  252. type:'del',
  253. content:'是否删除全部当前文件?',
  254. fileUrls:fileUrls,
  255. targetFileIds:targetFileIds
  256. };
  257. popupDelDialogRef.value.OpenDialog();
  258. }
  259. }
  260. //提交
  261. const UpdateTaskTarget = () => {
  262. const taskTargetFileVos = state?.targetFileList?.taskTargetFileVos || [];
  263. if(taskTargetFileVos.length == 0){
  264. uni.showToast({
  265. title: '请上传提交文件!',
  266. icon: 'none'
  267. });
  268. return false
  269. }
  270. state.delDialog = {
  271. type:'submit',
  272. content:'是否提交当前任务?',
  273. fileUrls:[],
  274. targetFileIds:[]
  275. };
  276. popupDelDialogRef.value.OpenDialog();
  277. }
  278. //重新提交
  279. const UpdateTaskTargetReset = () => {
  280. state.delDialog = {
  281. type:'submit',
  282. content:'是否重新编辑当前任务?',
  283. fileUrls:[],
  284. targetFileIds:[]
  285. };
  286. popupDelDialogRef.value.OpenDialog();
  287. }
  288. //确定删除 确定提交
  289. const DialogDelConfirm = () => {
  290. if(state.delDialog.type == 'del'){//单个删除 批量删除
  291. DelFileList();
  292. }else if(state.delDialog.type == 'submit') {//提交
  293. submitTaskTarget();
  294. }
  295. }
  296. const DelFileList = async() => {
  297. const res = await DeleteFileList({ fileUrls: state.delDialog.fileUrls })
  298. if (res.code !== 200) {
  299. uni.showToast({
  300. title: res.msg,
  301. icon: 'none'
  302. });
  303. return false
  304. }
  305. const resData = await DelTaskTargetFileList({
  306. targetId: state.targetId,
  307. targetFileIds: state.delDialog.targetFileIds
  308. })
  309. if (resData.code === 200) {
  310. uni.showToast({
  311. title: '删除成功!',
  312. icon: 'none'
  313. });
  314. GetTaskTargetFileList();
  315. }
  316. }
  317. //提交
  318. const submitTaskTarget = () => {
  319. updateTaskTarget(state.targetId).then(res => {
  320. if (res.code === 200) {
  321. uni.showToast({
  322. title: '提交成功!',
  323. icon: 'none'
  324. });
  325. GetTaskTargetFileList();
  326. }
  327. })
  328. }
  329. //返回
  330. const GoBack = () => {
  331. uni.navigateBack({
  332. delta: 1
  333. });
  334. }
  335. </script>
  336. <style scoped lang="scss">
  337. .page_content_height{
  338. display: flex;
  339. flex-direction: column;
  340. width: 100%;
  341. height: calc(100% - 226rpx);
  342. }
  343. .page_content {
  344. &.padding_btm {
  345. padding-bottom: 24rpx;
  346. .task_title {
  347. font-weight: 500;
  348. font-size: 32rpx;
  349. color: #333333;
  350. margin-top: 24rpx;
  351. }
  352. .task_class_collect {
  353. display: inline-flex;
  354. align-items: center;
  355. flex-wrap: wrap;
  356. width: 100%;
  357. margin-top: 16rpx;
  358. gap: 16rpx;
  359. .class_item {
  360. font-weight: 400;
  361. font-size: 24rpx;
  362. color: #999999;
  363. }
  364. }
  365. .task_time {
  366. display: flex;
  367. align-items: flex-start;
  368. width: 100%;
  369. margin-top: 16rpx;
  370. .time_day {
  371. display: inline-flex;
  372. align-items: center;
  373. flex-wrap: wrap;
  374. flex: 1;
  375. .time_item {
  376. font-weight: 400;
  377. font-size: 24rpx;
  378. line-height: 48rpx;
  379. color: #999999;
  380. &:nth-child(2) {
  381. margin: 0 8rpx;
  382. }
  383. &:nth-child(4) {
  384. color: #2E64FA;
  385. margin-left: 16rpx;
  386. }
  387. }
  388. }
  389. .task_status {
  390. display: inline-flex;
  391. align-items: center;
  392. height: 48rpx;
  393. padding: 0 12rpx;
  394. border-radius: 8rpx;
  395. font-weight: 400;
  396. font-size: 24rpx;
  397. &.status_pending {
  398. background: rgba(46, 100, 250, 0.1);
  399. color: #2E64FA;
  400. }
  401. &.status_published {
  402. background: rgba(82, 196, 26, 0.1);
  403. color: #2BC644;
  404. }
  405. &.status_closed {
  406. background: #6666661a;
  407. color: #666666;
  408. }
  409. }
  410. }
  411. .task_desc {
  412. margin-top: 24rpx;
  413. display: flex;
  414. width: 100%;
  415. padding-top: 24rpx;
  416. border-top: 2rpx solid #F3F3F3;
  417. font-weight: 400;
  418. font-size: 28rpx;
  419. color: #999999;
  420. line-height: 44rpx;
  421. box-sizing: border-box;
  422. position: relative;
  423. &.over {
  424. max-height: 168rpx;
  425. overflow: hidden;
  426. transition: all 0.25s;
  427. display: -webkit-box;
  428. -webkit-line-clamp: 3;
  429. -webkit-box-orient: vertical;
  430. }
  431. }
  432. .task_desc_all {
  433. display: flex;
  434. width: 100%;
  435. padding-top: 24rpx;
  436. border-top: 2rpx solid #F3F3F3;
  437. font-weight: 400;
  438. font-size: 28rpx;
  439. color: #999999;
  440. line-height: 44rpx;
  441. box-sizing: border-box;
  442. position: absolute;
  443. left: -9999px;
  444. top: 0;
  445. visibility: hidden; // 不可见但占据空间(不影响布局,因为absolute)
  446. pointer-events: none;
  447. }
  448. .expand_btn {
  449. width: 100%;
  450. height: 40rpx;
  451. background-color: #FFFFFF;
  452. display: flex;
  453. justify-content: flex-end;
  454. align-items: center;
  455. .expand_text {
  456. font-weight: 400;
  457. font-size: 28rpx;
  458. color: #2E64FA;
  459. margin-right: 8rpx;
  460. }
  461. .expand_icon {
  462. font-size: 32rpx !important;
  463. color: #2E64FA !important;
  464. }
  465. }
  466. }
  467. }
  468. .row_gap {
  469. background-color: #F8F9FD;
  470. width: 100%;
  471. height: 24rpx;
  472. }
  473. .target_status {
  474. width: 100%;
  475. display: flex;
  476. align-items: center;
  477. padding: 24rpx 0;
  478. border-bottom: 2rpx solid #F3F3F3;
  479. .target_tag{
  480. flex: 1;
  481. font-weight: 500;
  482. font-size: 32rpx;
  483. color: #333333;
  484. .info_text{
  485. flex-shrink: 0;
  486. margin-right: 12rpx;
  487. }
  488. }
  489. .status_tag{
  490. font-size: 24rpx;
  491. text-align: center;
  492. padding: 8rpx 12rpx;
  493. font-weight: 400;
  494. border-radius: 8rpx;
  495. flex-shrink: 0;
  496. &.notSubmitList {
  497. background: rgba(46,100,250,0.1);
  498. color: #2E64FA;
  499. }
  500. &.notReviewList {
  501. background: rgba(251,159,52,0.1);
  502. color: #FB9F34;
  503. }
  504. &.reviewReasonList {
  505. background: rgba(245,108,108,0.1);
  506. color: #F56C6C;
  507. }
  508. &.reviewList {
  509. background: rgba(43,198,68,0.1);
  510. color: #2BC644;
  511. }
  512. }
  513. }
  514. .upload_box{
  515. margin-top: 24rpx;
  516. width: 100%;
  517. background-color: #FAFBFF;
  518. border-radius: 20rpx;
  519. border: 2rpx dashed #CCCED4;
  520. display: flex;
  521. box-sizing: border-box;
  522. align-items: center;
  523. padding: 22rpx 0 22rpx 40rpx;
  524. .upload_icon{
  525. width: 64rpx;
  526. height: 64rpx;
  527. margin-right: 24rpx;
  528. flex-shrink: 0;
  529. }
  530. .upload_text{
  531. flex:1;
  532. display: flex;
  533. flex-direction: column;
  534. .upload_title{
  535. font-weight: 400;
  536. font-size: 28rpx;
  537. color: #666666;
  538. }
  539. .upload_desc{
  540. margin-top: 8rpx;
  541. font-weight: 400;
  542. font-size: 20rpx;
  543. color: #CCCED4;
  544. }
  545. }
  546. }
  547. .list_item {
  548. display: flex;
  549. align-items: center;
  550. width: 100%;
  551. padding: 20rpx 24rpx;
  552. background: #FFFFFF;
  553. border-radius: 20rpx;
  554. border: 2rpx solid #EBEEF5;
  555. box-sizing: border-box;
  556. margin-top: 24rpx;
  557. gap:20rpx;
  558. .file_icon{
  559. flex-shrink: 0;
  560. width: 80rpx;
  561. height: 80rpx;
  562. }
  563. .file_info{
  564. flex:1;
  565. display: flex;
  566. flex-direction: column;
  567. overflow: hidden;
  568. .file_name{
  569. width: 100%;
  570. font-weight: 500;
  571. font-size: 28rpx;
  572. color: #333333;
  573. overflow: hidden;
  574. white-space: nowrap;
  575. text-overflow: ellipsis;
  576. }
  577. .file_size{
  578. display: flex;
  579. width: 100%;
  580. gap: 20rpx;
  581. font-weight: 400;
  582. font-size: 24rpx;
  583. color: #999999;
  584. margin-top: 8rpx;
  585. }
  586. }
  587. .file_btn{
  588. flex-shrink: 0;
  589. display: flex;
  590. gap:24rpx;
  591. font-weight: 400;
  592. font-size: 28rpx;
  593. .del{
  594. color: #F56C6C;
  595. &.disabled{
  596. color: #C0C4CC;
  597. }
  598. }
  599. .download{
  600. color: #2E64FA;
  601. }
  602. }
  603. }
  604. .page_foot{
  605. position: fixed;
  606. display: flex;
  607. left: 0;
  608. right: 0;
  609. bottom: 0;
  610. padding: 20rpx 24rpx;
  611. background-color: #FFFFFF;
  612. gap: 32rpx;
  613. .del{
  614. display: flex;
  615. align-items: center;
  616. justify-content: center;
  617. width: 240rpx;
  618. height: 90rpx;
  619. box-sizing: border-box;
  620. border-radius: 8rpx;
  621. border: 2rpx solid #F56C6C;
  622. font-weight: 400;
  623. font-size: 28rpx;
  624. color: #F56C6C;
  625. &.disabled{
  626. color: #C0C4CC;
  627. border: 2rpx solid #C0C4CC;
  628. }
  629. }
  630. .submit {
  631. flex:1;
  632. height: 90rpx;
  633. background-color: #2E64FA;
  634. border-radius: 8rpx;
  635. display: flex;
  636. justify-content: center;
  637. align-items: center;
  638. font-weight: 500;
  639. font-size: 28rpx;
  640. color: #FFFFFF;
  641. }
  642. }
  643. </style>