taskDetail.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. <template>
  2. <view class="page_body">
  3. <!-- 头部 -->
  4. <nav-bar height="96" title="任务详情" :onlyTitle="true" :showHeaderborder="true" @GoBack="GoBack"></nav-bar>
  5. <!-- 吸顶 -->
  6. <uv-sticky style="top:98rpx">
  7. <view class="search_tabs" v-if="state.isSticky">
  8. <!-- 搜索框 -->
  9. <uni-easyinput class="search_box" v-model="state.searchWord" trim="all" :styles="state.searchInputStyles"
  10. :placeholderStyle="state.searchInputPlaceholderStyle" placeholder="请输入关键字搜索" @input="HandleSearchInput">
  11. <template #left>
  12. <image src="@/static/image/overview/search.png" class="search_icon"></image>
  13. </template>
  14. </uni-easyinput>
  15. <view class="scroll_select">
  16. <uni-data-select v-for="(item,index) in state.selectData" :key="item.prop" v-model="state.selectProp[item.prop]" :clear="false" :placeholder="`请选择`" :localdata="item.list" @change="(val) => ChangeSelectData(val,index,item.list)"></uni-data-select>
  17. </view>
  18. <scroll-view class="scroll_tabs" scroll-x="true" scroll-left="0" :show-scrollbar="false">
  19. <view :class="['tab_item',{'selected':item.value==state.tabsSelected}]" v-for="item in state.tabList"
  20. :key="item.value" @click="SelectTabsValue(item.value)">
  21. {{item.label}}
  22. </view>
  23. </scroll-view>
  24. </view>
  25. </uv-sticky>
  26. <view class="scroll_view_box">
  27. <scroll-view
  28. class="scroll_view_y"
  29. :scroll-top="state.scrollTop"
  30. scroll-y="true"
  31. :refresher-enabled="false"
  32. :enable-back-to-top="true"
  33. :show-scrollbar="false"
  34. :scroll-with-animation="true"
  35. refresher-default-style="none"
  36. refresher-background="#F8F9FD"
  37. :refresher-triggered="state.isRefreshing"
  38. @scrolltolower="OnLoadMore"
  39. @refresherrefresh="OnRefresh"
  40. @scroll="OnScroll">
  41. <view class="refresh_loading" v-if="state.isRefreshing"><uni-load-more status="loading" /></view>
  42. <view class="page_content padding_btm">
  43. <view class="task_title">{{state?.details?.taskName}}</view>
  44. <view class="task_class_collect">
  45. <text class="class_item">{{state?.details?.departmentName}}</text>
  46. <text class="class_item">{{state?.details?.materialCategoryName}}</text>
  47. <text class="class_item">{{state?.details?.createdBy}}</text>
  48. </view>
  49. <view class="task_time">
  50. <view class="time_day">
  51. <text class="time_item">{{state?.details?.startTime}}</text>
  52. <text class="time_item">至</text>
  53. <text class="time_item">{{state?.details?.endTime}}</text>
  54. <text class="time_item" v-if="state.taskStatus!== 2 && remainingDays(state?.details?.endTime) > 0">剩余{{remainingDays(state?.details?.endTime)}}天</text>
  55. </view>
  56. <view :class="['task_status', statusClassMap[state.taskStatus]]">
  57. {{taskStatusMap[state.taskStatus]}}
  58. </view>
  59. </view>
  60. <view :class="['task_desc',{'over':!state.isExpand}]">
  61. 采集要求:{{state?.details?.collectionRequire}}
  62. </view>
  63. <view class="task_desc_all">
  64. 采集要求:{{state?.details?.collectionRequire}}
  65. </view>
  66. <view class="expand_btn" v-if="state.showExpandBtn" @click="toggleExpand"><text
  67. class="expand_text">{{!state.isExpand?'展开':'收起'}}</text><uni-icons class="expand_icon"
  68. :type="!state.isExpand?'down':'up'"></uni-icons></view>
  69. </view>
  70. <!-- 间隔 -->
  71. <view class="row_gap"></view>
  72. <!-- 吸顶 -->
  73. <!-- <uv-sticky style="top:98rpx"> -->
  74. <view class="search_tabs">
  75. <!-- 搜索框 -->
  76. <uni-easyinput class="search_box" v-model="state.searchWord" trim="all" :styles="state.searchInputStyles"
  77. :placeholderStyle="state.searchInputPlaceholderStyle" placeholder="请输入关键字搜索" @input="HandleSearchInput">
  78. <template #left>
  79. <image src="@/static/image/overview/search.png" class="search_icon"></image>
  80. </template>
  81. </uni-easyinput>
  82. <view class="scroll_select">
  83. <uni-data-select v-for="(item,index) in state.selectData" :key="item.prop" v-model="state.selectProp[item.prop]" :clear="false" :placeholder="`请选择`" :localdata="item.list" @change="(val) => ChangeSelectData(val,index,item.list)"></uni-data-select>
  84. </view>
  85. <scroll-view class="scroll_tabs" scroll-x="true" scroll-left="0" :show-scrollbar="false">
  86. <view :class="['tab_item',{'selected':item.value==state.tabsSelected}]" v-for="item in state.tabList"
  87. :key="item.value" @click="SelectTabsValue(item.value)">
  88. {{item.label}}
  89. </view>
  90. </scroll-view>
  91. </view>
  92. <!-- </uv-sticky> -->
  93. <view class="page_content page_content_data">
  94. <view class="total">共 {{state[`${state.tabsSelected}List`]?.length || 0}} 人</view>
  95. <view class="list_item" v-for="item in state.tabListData" :Key="item.id">
  96. <view class="item_name_file">
  97. <view class="name_file">
  98. <text class="name">{{item.targetName}}</text>
  99. <text class="file_num" v-if="state?.[`${state.tabsSelected}Header`]?.includes('fileNum')">文件数量:{{item?.fileNum || 0}}</text>
  100. </view>
  101. <view class="btn" @click="OpenPreviewFileDialog(item.taskTargetFileVos)">查看</view>
  102. </view>
  103. <view class="item_info">
  104. <template v-for="prop in state?.[`${state.tabsSelected}Header`]">
  105. <text v-if="['targetName','fileNum','reviewBy','reviewTime'].indexOf(prop) == -1" class="info_text">{{item[prop]}}</text>
  106. </template>
  107. </view>
  108. <view class="item_info" v-if="state?.[`${state.tabsSelected}Header`]?.includes('reviewBy')">
  109. <text class="info_text">审核人:{{item.reviewBy}}</text>
  110. <text class="info_text">{{item.reviewTime}}</text>
  111. </view>
  112. </view>
  113. <view class="no_data" v-if="!state.isLoading && state.tabListData.length == 0">
  114. <image class="no_data_img" src="@/static/image/bg/no_data.png"></image>
  115. <text class="no_data_text">暂无数据</text>
  116. </view>
  117. </view>
  118. <uni-load-more v-if="state.tabListData.length > 0" :status="state.loadStatus" />
  119. </scroll-view>
  120. </view>
  121. <customPopupDialog class="file_preview" ref="popupFileDialogRef" title="查看文件" dialogWidth="670" :isMaskClick="false" :showDialogFooter="false">
  122. <view class="dialog_content_file">
  123. <view class="file_list_item" v-for="item in state.fileDialog.fileList" :Key="item.id">
  124. <image class="file_icon" src="@/static/image/icon/file.png"></image>
  125. <view class="file_info">
  126. <view class="file_name">{{item.fileName}}</view>
  127. <view class="file_size">
  128. <text>{{getFileSize(item.fileSize)}}</text>
  129. <text>{{ item.createTime }}</text>
  130. </view>
  131. </view>
  132. <view class="file_btn">
  133. <text class="preview">预览</text>
  134. </view>
  135. </view>
  136. </view>
  137. </customPopupDialog>
  138. </view>
  139. </template>
  140. <script setup>
  141. import uniEasyinput from '@/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue';
  142. import uniDataSelect from '@/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue';
  143. import customPopupDialog from '@/components/customPopupDialog.vue';
  144. import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue';
  145. import uvSticky from '@/uni_modules/uv-sticky/components/uv-sticky/uv-sticky.vue'; //吸顶
  146. import navBar from '@/components/navBar.vue';
  147. import { remainingDays,getFileSize } from '@/common/common.js';
  148. import {
  149. GetCollectionTask,
  150. getTaskTargetList,
  151. getTaskSelectCommon
  152. } from '@/reqApi/notification.js';
  153. import {
  154. onLoad
  155. } from '@dcloudio/uni-app';
  156. import {
  157. reactive,
  158. ref,
  159. nextTick,
  160. getCurrentInstance,
  161. onMounted
  162. } from 'vue';
  163. const state = reactive({
  164. taskId: '', //任务id
  165. taskStatus:'',//任务状态 0-未开始 1-进行中 2-结束
  166. searchWord: '', //搜索关键词
  167. searchInputStyles: { //搜索框样式
  168. borderColor: '#DCDFE6',
  169. color: '#333333'
  170. },
  171. searchInputPlaceholderStyle: 'color: #C0C4CC;fontSize: 28rpx', //搜索框样式
  172. tabsSelected: '', //默认选中tab值
  173. tabList: [], //tab列表
  174. reviewTabList: [{
  175. label: '待审核',
  176. value: 'notReview'
  177. }, {
  178. label: '已审核',
  179. value: 'review'
  180. }, {
  181. label: '已驳回',
  182. value: 'reviewReason'
  183. }, {
  184. label: '待提交',
  185. value: 'notSubmit'
  186. }], //需审核
  187. noReviewTabList: [{
  188. label: '待提交',
  189. value: 'notSubmit'
  190. }, {
  191. label: '已提交',
  192. value: 'review'
  193. }], //无需审核
  194. showExpandBtn: false, //是否显示展开按钮
  195. isExpand: false, //是否展开
  196. pageSize: 50,
  197. pageNum: 1,
  198. scrollTop: 0,
  199. oldScrollTop: 0,
  200. isRefreshing: false, //设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发
  201. isLoading: true, //加载中
  202. noMoreData: false, //没有更多数据了
  203. loadStatus: 'more', //loading状态
  204. details: {}, //详情信息
  205. selectData:[],//筛选项
  206. selectProp:{},//筛选项字段及值
  207. notReviewList: [],//待审核
  208. notSubmitList: [],//待提交
  209. reviewList: [],//已审核
  210. reviewReasonList: [],//已驳回
  211. notReviewPagess: 0,//待审核分页
  212. notSubmitPages: 0,//待提交分页
  213. reviewPagess: 0,//已审核分页
  214. reviewReasonPagess: 0,//已驳回分页
  215. notReviewHeader: [],//待审核表头
  216. notSubmitHeader: [],//待提交表头
  217. reviewHeader: [],//已审核表头
  218. reviewReasonHeader: [],//已驳回表头
  219. tabListData: [], //列表数据
  220. searchBoxTop:0,//搜索框距离顶部的高度
  221. isSticky:false,//是否吸顶
  222. fileDialog:{//文件预览
  223. fileList:[]
  224. }
  225. });
  226. const statusClassMap = {
  227. 0: 'status_pending',
  228. 1: 'status_published',
  229. 2: 'status_closed'
  230. };
  231. const taskStatusMap = {
  232. 0: '待开始',
  233. 1: '进行中',
  234. 2: '已结束'
  235. };
  236. const popupFileDialogRef = ref(null)
  237. onLoad((option) => {
  238. state.taskId = option.taskId;
  239. state.taskStatus = option.taskStatus;
  240. })
  241. onMounted(() => {
  242. QueryCollectionTask();//获取指定的采集任务详情
  243. QueryTaskSelectCommon();//获取当前任务的筛选表头和数据表的表头
  244. OnLoadData(true,true); // 数据加载完成后触发 checkTextOverflow
  245. });
  246. //获取指定的采集任务详情
  247. const QueryCollectionTask = () => {
  248. GetCollectionTask(state.taskId).then(res=>{
  249. if(res.code == 200){
  250. state.details = res?.data || {};
  251. // 审核机制 0-无需审核 1-需要审核
  252. state.tabList = state.details.auditMechanism === 1 ? state.reviewTabList:state.noReviewTabList;
  253. state.tabsSelected = state.tabList?.[0]?.value || '';
  254. }
  255. })
  256. }
  257. //获取当前任务的筛选表头和数据表的表头
  258. const QueryTaskSelectCommon = () => {
  259. getTaskSelectCommon(state.taskId).then(res=>{
  260. if(res.code == 200){
  261. const list = res?.data?.commonSelect || [];
  262. const selectList = list.map(item=>({
  263. ...item,
  264. text:item.label,
  265. value:item.value ?? ''
  266. }))
  267. if(list.length > 0){
  268. const prop = list?.[0]?.prop || '';
  269. const value = list?.[0]?.value ?? '';
  270. //筛选项字段及字段对应的值
  271. state.selectData.push({
  272. prop:prop,
  273. list:selectList
  274. })
  275. state.selectProp[prop] = value;
  276. }
  277. const notReviewTableHeader = res?.data?.notReviewTableHeader || [];
  278. const notSubmitTableHeader = res?.data?.notSubmitTableHeader || [];
  279. const tableHeader = res?.data?.tableHeader || [];
  280. const tableHeaderProp = tableHeader.filter(item=>item.display).map(item=>item.prop);
  281. state.notReviewHeader = notReviewTableHeader.filter(item=>item.display).map(item=>item.prop);//待审核表头
  282. state.notSubmitHeader = notSubmitTableHeader.filter(item=>item.display).map(item=>item.prop);//待提交表头
  283. state.reviewHeader = tableHeaderProp;//已审核表头
  284. state.reviewReasonHeader = tableHeaderProp;//已驳回表头
  285. }
  286. })
  287. }
  288. //切换下拉框数据
  289. const ChangeSelectData = (val,index,list) => {
  290. const childrenData = list.find(item=>item.value === val)?.children || [];
  291. if(childrenData.length > 0){
  292. let childrenList = childrenData.map(item=>({
  293. ...item,
  294. text:item.label,
  295. value:item.value ?? ''
  296. }))
  297. const titleName = childrenData?.[0]?.titleName || '';
  298. const value = childrenData?.[0]?.value ?? '';
  299. console.log(childrenData?.[0]?.value,value,1232323,value!=='')
  300. const prop = childrenData?.[0]?.prop;
  301. if(value!==''){//添加全部
  302. childrenList.unshift({
  303. text:titleName,
  304. value:''
  305. })
  306. }else{
  307. const defaultVal = childrenList?.[0]?.value ?? '';
  308. state.selectProp[prop] = defaultVal;
  309. }
  310. state.selectData[index + 1] = {
  311. prop:prop,
  312. list:childrenList
  313. }
  314. }else{
  315. state.selectData.splice(index + 1);//删除
  316. Object.keys(state.selectProp).forEach((key,i)=>{
  317. if(i >= index + 1){
  318. delete state.selectProp[key]
  319. }
  320. })
  321. }
  322. OnLoadData(true);
  323. }
  324. const checkTextOverflow = () => {
  325. nextTick(() => {
  326. const instance = getCurrentInstance();
  327. // 安全保护
  328. if (!instance || !instance.proxy) {
  329. // 备用方案:全局查询(要求元素 class 唯一)
  330. let taskDescAllHeight = 0,
  331. taskDescHeight = 0;
  332. const query = uni.createSelectorQuery();
  333. query.select('.task_desc_all').boundingClientRect((rect) => {
  334. taskDescAllHeight = rect?.height || 0;
  335. });
  336. query.select('.task_desc').boundingClientRect((rect) => {
  337. taskDescHeight = rect?.height || 0;
  338. });
  339. query.select('.page_content_data').boundingClientRect((rect) => {
  340. state.searchBoxTop = rect?.top || 0;
  341. });
  342. query.exec(() => {
  343. // 所有回调执行完毕后触发
  344. state.showExpandBtn = taskDescAllHeight > taskDescHeight + 1;
  345. });
  346. return;
  347. }
  348. let taskDescAllHeight = 0,
  349. taskDescHeight = 0;
  350. const query = uni.createSelectorQuery().in(instance.proxy);
  351. query.select('.task_desc_all').boundingClientRect((rect) => {
  352. taskDescAllHeight = rect?.height || 0;
  353. });
  354. query.select('.task_desc').boundingClientRect((rect) => {
  355. taskDescHeight = rect?.height || 0;
  356. });
  357. query.select('.page_content_data').boundingClientRect((rect) => {
  358. state.searchBoxTop = rect?.top || 0;
  359. });
  360. query.exec(() => {
  361. // 所有回调执行完毕后触发
  362. state.showExpandBtn = taskDescAllHeight > taskDescHeight + 1;
  363. });
  364. });
  365. }
  366. // 展开收起切换
  367. const toggleExpand = () => {
  368. state.isExpand = !state.isExpand;
  369. }
  370. //切换tab
  371. const SelectTabsValue = (val) => {
  372. state.tabsSelected = val;
  373. OnLoadData(true);
  374. }
  375. //搜索
  376. const HandleSearchInput = (val) => {
  377. state.searchWord = val;
  378. OnLoadData(true);
  379. }
  380. const ToSafeArr = (val) => {
  381. if (Array.isArray(val)) return val
  382. return val ? [val] : []
  383. }
  384. /*
  385. *详情
  386. * initPage:初始分页 从第一开始
  387. * initData:初始加载
  388. */
  389. const OnLoadData = (initPage,initData = false) => {
  390. state.isLoading = true;
  391. state.loadStatus = 'loading';
  392. if (initPage) {
  393. state.pageNum = 1; //如果是下拉刷新、重新查询 默认加载第一页
  394. getTaskTargetList({
  395. taskId: state.taskId,
  396. queryStr: state.searchWord,
  397. ...state.selectProp
  398. }).then(res => {
  399. if (res.code == 200) {
  400. const data = res?.data ?? {};
  401. // 列表全部数据
  402. state.notSubmitList = ToSafeArr(data.notSubmitList);//待提交
  403. state.notReviewList = ToSafeArr(data.notReviewList);//待审核
  404. const reviewData = ToSafeArr(data.reviewList);
  405. const submitData = ToSafeArr(data.submitList);
  406. state.reviewList = reviewData.length ? reviewData : submitData;//已审核
  407. state.reviewReasonList = ToSafeArr(data.reviewReasonList);//已驳回
  408. //处理分页-----
  409. const total = state[`${state.tabsSelected}List`]?.length || 0;
  410. state[`${state.tabsSelected}Pages`] = Math.ceil(total / state.pageSize);//总页数
  411. //默认加载
  412. state.tabListData = state?.[`${state.tabsSelected}List`]?.slice(0, state.pageSize) || [];
  413. //没有更多了
  414. state.noMoreData = state.pageNum == state[`${state.tabsSelected}Pages`];
  415. //分页+1
  416. state.pageNum++;
  417. state.isLoading = false;
  418. state.isRefreshing = false;//下拉刷新未被触发
  419. state.loadStatus = state.noMoreData?'no-more':'more';
  420. if(initData){
  421. checkTextOverflow();
  422. }
  423. }
  424. }).finally(() => {
  425. //返回到页面顶部
  426. if (initPage) {
  427. GoTop();
  428. }
  429. })
  430. }else{
  431. const start = (state.pageNum - 1) * state.pageSize;
  432. const end = start + state.pageSize;
  433. const list = state?.[`${state.tabsSelected}List`]?.slice(start, end) || [];
  434. state.tabListData = [...state.tabListData, ...list];
  435. state.noMoreData = state.pageNum == state[`${state.tabsSelected}Pages`];
  436. state.pageNum++;
  437. setTimeout(() => {
  438. state.isLoading = false;
  439. state.isRefreshing = false; //下拉刷新未被触发
  440. state.loadStatus = state.noMoreData?'no-more':'more';
  441. }, 0)
  442. }
  443. }
  444. // 自定义下拉刷新被触发 下拉刷新
  445. const OnRefresh = () => {
  446. state.isRefreshing = true; //下拉刷新已经被触发
  447. OnLoadData(true);
  448. }
  449. //滚动到底部/右边 触发上拉刷新
  450. const OnLoadMore = () => {
  451. if (state.isLoading || state.noMoreData) return;
  452. OnLoadData(false);
  453. }
  454. // 滚动时触发
  455. const OnScroll = (e) => {
  456. const scrollTop = e.detail.scrollTop;
  457. if(scrollTop > state.searchBoxTop){
  458. state.isSticky = true;
  459. }else{
  460. state.isSticky = false;
  461. }
  462. state.oldScrollTop = scrollTop;
  463. }
  464. //打开预览弹框
  465. const OpenPreviewFileDialog = (files) => {
  466. console.log(files)
  467. state.fileDialog.fileList = files || [];
  468. popupFileDialogRef.value.OpenDialog();
  469. }
  470. //返回到顶部
  471. const GoTop = () => {
  472. // 解决view层不同步的问题
  473. state.scrollTop = state.oldScrollTop;
  474. nextTick(() => {
  475. state.scrollTop = 0
  476. });
  477. }
  478. //返回
  479. const GoBack = () => {
  480. uni.navigateBack({
  481. delta: 1
  482. });
  483. }
  484. </script>
  485. <style scoped lang="scss">
  486. .page_body{
  487. height: 100%;
  488. min-height: auto;
  489. .scroll_view_box{
  490. width: 100%;
  491. display: flex;
  492. flex-direction: column;
  493. height: calc(100% - 96rpx);
  494. }
  495. .scroll_view_y {
  496. height: 100%;
  497. .refresh_loading {
  498. padding: 10rpx 0;
  499. }
  500. }
  501. }
  502. .page_content {
  503. &.padding_btm {
  504. padding-bottom: 24rpx;
  505. .task_title {
  506. font-weight: 500;
  507. font-size: 32rpx;
  508. color: #333333;
  509. margin-top: 24rpx;
  510. }
  511. .task_class_collect {
  512. display: inline-flex;
  513. align-items: center;
  514. flex-wrap: wrap;
  515. width: 100%;
  516. margin-top: 16rpx;
  517. gap: 16rpx;
  518. .class_item {
  519. font-weight: 400;
  520. font-size: 24rpx;
  521. color: #999999;
  522. }
  523. }
  524. .task_time {
  525. display: flex;
  526. align-items: flex-start;
  527. width: 100%;
  528. margin-top: 16rpx;
  529. .time_day {
  530. display: inline-flex;
  531. align-items: center;
  532. flex-wrap: wrap;
  533. flex: 1;
  534. .time_item {
  535. font-weight: 400;
  536. font-size: 24rpx;
  537. line-height: 48rpx;
  538. color: #999999;
  539. &:nth-child(2) {
  540. margin: 0 8rpx;
  541. }
  542. &:nth-child(4) {
  543. color: #2E64FA;
  544. margin-left: 16rpx;
  545. }
  546. }
  547. }
  548. .task_status {
  549. display: inline-flex;
  550. align-items: center;
  551. height: 48rpx;
  552. padding: 0 12rpx;
  553. border-radius: 8rpx;
  554. font-weight: 400;
  555. font-size: 24rpx;
  556. &.status_pending {
  557. background: rgba(46, 100, 250, 0.1);
  558. color: #2E64FA;
  559. }
  560. &.status_published {
  561. background: rgba(82, 196, 26, 0.1);
  562. color: #2BC644;
  563. }
  564. &.status_closed {
  565. background: #6666661a;
  566. color: #666666;
  567. }
  568. }
  569. }
  570. .task_desc {
  571. margin-top: 24rpx;
  572. display: flex;
  573. width: 100%;
  574. padding-top: 24rpx;
  575. border-top: 2rpx solid #F3F3F3;
  576. font-weight: 400;
  577. font-size: 28rpx;
  578. color: #999999;
  579. line-height: 44rpx;
  580. box-sizing: border-box;
  581. position: relative;
  582. &.over {
  583. max-height: 168rpx;
  584. overflow: hidden;
  585. transition: all 0.25s;
  586. display: -webkit-box;
  587. -webkit-line-clamp: 3;
  588. -webkit-box-orient: vertical;
  589. }
  590. }
  591. .task_desc_all {
  592. display: flex;
  593. width: 100%;
  594. padding-top: 24rpx;
  595. border-top: 2rpx solid #F3F3F3;
  596. font-weight: 400;
  597. font-size: 28rpx;
  598. color: #999999;
  599. line-height: 44rpx;
  600. box-sizing: border-box;
  601. position: absolute;
  602. left: -9999px;
  603. top: 0;
  604. visibility: hidden; // 不可见但占据空间(不影响布局,因为absolute)
  605. pointer-events: none;
  606. }
  607. .expand_btn {
  608. width: 100%;
  609. height: 40rpx;
  610. background-color: #FFFFFF;
  611. display: flex;
  612. justify-content: flex-end;
  613. align-items: center;
  614. .expand_text {
  615. font-weight: 400;
  616. font-size: 28rpx;
  617. color: #2E64FA;
  618. margin-right: 8rpx;
  619. }
  620. .expand_icon {
  621. font-size: 32rpx !important;
  622. color: #2E64FA !important;
  623. }
  624. }
  625. }
  626. }
  627. .row_gap {
  628. background-color: #F8F9FD;
  629. width: 100%;
  630. height: 24rpx;
  631. }
  632. :deep(.search_tabs){
  633. display: flex;
  634. width: 100%;
  635. flex-direction: column;
  636. background-color: #FFFFFF;
  637. .search_box {
  638. display: flex;
  639. align-items: center;
  640. box-sizing: border-box;
  641. width: 100%;
  642. padding: 24rpx;
  643. box-sizing: border-box;
  644. background-color: #FFFFFF;
  645. .is-input-border {
  646. border-radius: 8rpx;
  647. border: 2rpx solid #DCDFE6;
  648. border-color: #DCDFE6 !important;
  649. }
  650. .search_icon {
  651. width: 32rpx;
  652. height: 32rpx;
  653. margin-left: 24rpx;
  654. }
  655. .uni-easyinput__content-input {
  656. padding-left: 8rpx !important;
  657. font-size: 28rpx;
  658. color: #333333;
  659. height: 72rpx;
  660. }
  661. }
  662. }
  663. .scroll_select{
  664. width: 100%;
  665. display: flex;
  666. padding: 0 24rpx 24rpx;
  667. box-sizing: border-box;
  668. gap: 32rpx;
  669. :deep(.uni-stat__select){
  670. flex: 1;
  671. max-width: calc((100% - 32rpx * 2) / 3);
  672. min-width: 212rpx;
  673. width: auto;
  674. .uni-select{
  675. height: 72rpx;
  676. border-radius: 8rpx;
  677. border: 2rpx solid #DCDFE6;
  678. font-weight: 400;
  679. font-size: 28rpx;
  680. color: #333333;
  681. .uni-select__input-box{
  682. height: 72rpx;
  683. }
  684. .uni-icons{
  685. color: #909399;
  686. font-size: 24rpx;
  687. }
  688. }
  689. }
  690. }
  691. .scroll_tabs {
  692. margin-top:0;
  693. background-color: #FFFFFF;
  694. }
  695. .total {
  696. width: 100%;
  697. display: flex;
  698. font-weight: 400;
  699. font-size: 28rpx;
  700. color: #333333;
  701. padding: 24rpx 0;
  702. border-bottom: 2rpx solid #F3F3F3;
  703. }
  704. .list_item {
  705. display: flex;
  706. flex-direction: column;
  707. width: 100%;
  708. padding: 24rpx 0;
  709. border-bottom: 2rpx solid #F3F3F3;
  710. .item_name_file{
  711. display: flex;
  712. width: 100%;
  713. align-items: center;
  714. gap: 20rpx;
  715. .name_file{
  716. flex:1;
  717. gap: 20rpx;
  718. display: flex;
  719. align-items: center;
  720. .name{
  721. font-weight: 500;
  722. font-size: 32rpx;
  723. color: #333333;
  724. }
  725. .file_num{
  726. font-weight: 400;
  727. font-size: 24rpx;
  728. color: #2E64FA;
  729. }
  730. }
  731. .btn{
  732. width: 104rpx;
  733. height: 64rpx;
  734. border-radius: 8rpx;
  735. border: 2rpx solid #2E64FA;
  736. font-weight: 400;
  737. font-size: 28rpx;
  738. color: #2E64FA;
  739. display: inline-flex;
  740. align-items: center;
  741. justify-content: center;
  742. }
  743. }
  744. .item_info{
  745. margin-top: 16rpx;
  746. display: flex;
  747. gap: 16rpx;
  748. align-items: center;
  749. flex-wrap: wrap;
  750. .info_text{
  751. font-weight: 400;
  752. font-size: 24rpx;
  753. color: #999999;
  754. flex-shrink: 0;
  755. }
  756. }
  757. }
  758. .no_data{
  759. margin-top: 24rpx;
  760. }
  761. .file_preview{
  762. :deep(.dialog_content){
  763. padding: 24rpx 0 32rpx;
  764. }
  765. .dialog_content_file{
  766. display: flex;
  767. width: 100%;
  768. max-height: 440rpx;
  769. padding: 0 24rpx;
  770. box-sizing: border-box;
  771. overflow-y: auto;
  772. flex-direction: column;
  773. .file_list_item {
  774. display: flex;
  775. align-items: center;
  776. width: 100%;
  777. padding: 20rpx 24rpx;
  778. background: #FFFFFF;
  779. border-radius: 20rpx;
  780. border: 2rpx solid #EBEEF5;
  781. box-sizing: border-box;
  782. margin-top: 40rpx;
  783. &:nth-child(1){
  784. margin-top: 0;
  785. }
  786. gap:20rpx;
  787. .file_icon{
  788. flex-shrink: 0;
  789. width: 80rpx;
  790. height: 80rpx;
  791. }
  792. .file_info{
  793. flex:1;
  794. display: flex;
  795. flex-direction: column;
  796. overflow: hidden;
  797. .file_name{
  798. width: 100%;
  799. font-weight: 500;
  800. font-size: 28rpx;
  801. color: #333333;
  802. overflow: hidden;
  803. white-space: nowrap;
  804. text-overflow: ellipsis;
  805. }
  806. .file_size{
  807. display: flex;
  808. width: 100%;
  809. gap: 20rpx;
  810. font-weight: 400;
  811. font-size: 24rpx;
  812. color: #999999;
  813. margin-top: 8rpx;
  814. }
  815. }
  816. .file_btn{
  817. flex-shrink: 0;
  818. display: flex;
  819. gap:24rpx;
  820. font-weight: 400;
  821. font-size: 28rpx;
  822. .preview{
  823. color: #2E64FA;
  824. }
  825. }
  826. }
  827. }
  828. }
  829. </style>