index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. <template>
  2. <page-meta root-font-size="system" />
  3. <view class="index_container">
  4. <view class="search_container">
  5. <uni-row>
  6. <uni-col :xs="3" :sm="2">
  7. <view @click="openPopup" class="popup_button_container">
  8. <text class="ygoa_icon icon-filter"></text>
  9. <!-- <text class="button_text">筛选</text> -->
  10. </view>
  11. </uni-col>
  12. <view class="search_bar">
  13. <!-- 输入框搜索 -->
  14. <uni-col v-if="0 == searchItem" :xs="17" :sm="19">
  15. <uni-search-bar @confirm="searchBarConfirm" @cancel="cancelSearch" @blur="searchBarOnBlur"
  16. clearButton="none" placeholder="搜索栏">
  17. <template v-slot:searchIcon>
  18. <uni-icons type="search" size="calc(30px + .5*(1rem - 16px))"></uni-icons>
  19. </template>
  20. </uni-search-bar>
  21. </uni-col>
  22. <!-- 类型 下拉框搜索 -->
  23. <uni-col v-else-if="1 == searchItem" :xs="16" :sm="18">
  24. <picker class="picker_container" @change="bindPickerChange" :value="pickerItem"
  25. :range="pickerItems" range-key="modelName">
  26. <view class="uni-input input_text">
  27. {{ pickerItems[pickerItem].modelName }}
  28. </view>
  29. </picker>
  30. <view @click="search(pickerItems[pickerItem].modelId)" class="picker_button_container">
  31. <uni-icons type="search" size="calc(30px + .5*(1rem - 16px))"></uni-icons>
  32. <text class="button_text">搜索</text>
  33. </view>
  34. </uni-col>
  35. <!-- 时间范围搜索 -->
  36. <uni-col v-else-if="2 == searchItem" :xs="16" :sm="18">
  37. <view class="datetime_picker_container">
  38. <uni-datetime-picker type="daterange" @change="datetimePickerChange" @clear="cancelSearch"
  39. :border="false" />
  40. </view>
  41. </uni-col>
  42. <!-- 清空筛选按钮 -->
  43. <uni-col :xs="2" :sm="2">
  44. <view @click="cancelSearch" class="clear_button_container">
  45. <uni-icons type="clear" size="calc(24px + .5*(1rem - 16px))" color="#999"></uni-icons>
  46. </view>
  47. </uni-col>
  48. </view>
  49. </uni-row>
  50. </view>
  51. <view class="segmented_control_container">
  52. <uni-segmented-control :current="current" :values="items" @clickItem="clickSegmentItem" styleType="text"
  53. activeColor="#409eff"></uni-segmented-control>
  54. </view>
  55. <view class="process_list">
  56. <process-list ref="processListRef" @clickCancel="handleToCancelProcess" @clickSegment="getProcessData"
  57. @clickItem="handleToProcessDetail" @scrollToBottom="getProcessPage" :current="current" :pSize="5"
  58. :pageNo="1"></process-list>
  59. </view>
  60. <view class="popup_container">
  61. <uni-popup ref="searchItemPopup" type="bottom">
  62. <!-- 弹窗标题 -->
  63. <!-- <view class="popup-title">流程类型分类</view> -->
  64. <!-- 流程分类列表 -->
  65. <uni-section title="流程类型" type="line" class="uni-section">
  66. <uni-collapse :accordion="true">
  67. <uni-list class="flow-category-list">
  68. <!-- 一级分类:流程类型(遍历ftypeList) -->
  69. <uni-collapse-item
  70. class="flow-type-group"
  71. :open="false"
  72. :show-animation="true"
  73. v-for="(type, typeIdx) in flowList.ftypeList"
  74. :key="typeIdx"
  75. :title="type.typeName"
  76. >
  77. <template v-slot:title>
  78. <view class="group-header">
  79. <!-- 流程类型图标(可自定义) -->
  80. <uni-icons type="list" size="24rpx" class="group-icon" />
  81. <!-- 流程类型名称 -->
  82. <text class="group-name">{{ type.typeName }}</text>
  83. <!-- 流程类型下的总数量角标 -->
  84. <!-- <view class="badge" v-if="getTypeItemCount(type.typeId) > 0">
  85. {{ getTypeItemCount(type.typeId) }}
  86. </view> -->
  87. <uni-badge :text="getTypeItemCount(type.typeId)" v-if="getTypeItemCount(type.typeId) > 0"></uni-badge>
  88. </view>
  89. </template>
  90. <view v-for="(item, index) in flowList.fList" :index="index" :key="item.modelId">
  91. <!-- <uni-list-item @click="searchByModelId(item)" v-if="type.typeId === item.typeId.typeId"
  92. clickable class=""> -->
  93. <view
  94. @click="searchByModelId(item)"
  95. v-if="type.typeId === item.typeId.typeId"
  96. style="padding: 16rpx 60rpx; background: #fff; border-bottom: 1px solid #f5f5f7;"
  97. class="flow-item-sub"
  98. >
  99. <view style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
  100. <text class="sub-item-title">{{ item.modelName }}</text>
  101. <uni-badge :text="getModelItemCount(item.modelId)" v-if="getModelItemCount(item.modelId) > 0"></uni-badge>
  102. </view>
  103. <!-- <view class="sub-item-title"> -->
  104. <!-- <text>{{ item.modelName }}</text> -->
  105. <!-- 单个流程项角标(根据modelId统计待办数量) -->
  106. <!-- <view class="badge small-badge" v-if="getModelItemCount(item.modelId) > 0">
  107. {{ getModelItemCount(item.modelId) }}
  108. </view> -->
  109. <!-- </view> -->
  110. </view>
  111. <!-- </uni-list-item> -->
  112. </view>
  113. </uni-collapse-item>
  114. </uni-list>
  115. </uni-collapse>
  116. </uni-section>
  117. <!-- <uni-section title="发起人" type="line" @click="clickSearchItem('createUser')"></uni-section>
  118. <uni-section title="时间" type="line" @click="clickSearchItem('createTime')"></uni-section> -->
  119. </uni-popup>
  120. </view>
  121. </view>
  122. </template>
  123. <script setup lang="ts">
  124. import processList from '@/components/ygoa/processList.vue'
  125. import { onShow, onLoad } from '@dcloudio/uni-app'
  126. import { reactive, ref, onMounted } from 'vue';
  127. import $tab from '@/plugins/tab.js'
  128. import $modal from '@/plugins/modal.js'
  129. import { getUserProcess, getUserProcessed, getUserProcessing, getUserAllProcess, getUserCopyProcess, cancelProcessFlow, getProcessList, getProcessFormInfo } from '@/api/process';
  130. import { useUserStore } from '@/store/user';
  131. onMounted(() => {
  132. uni.$on('ReloadProcessData', () => {
  133. new Promise((resolve, reject) => {
  134. processListRef.value.onClickItem()
  135. })
  136. })
  137. })
  138. onShow(() => {
  139. uni.$emit('showTabBarBadge')
  140. })
  141. const userStore = useUserStore()
  142. onLoad(({ insId, tinsId, insName, control }) => {
  143. if (insId) {
  144. const username = userStore.user.name
  145. getProcessFormInfo( userStore.user.useId, insId ).then(({ returnParams }) => {
  146. //流程流转的最后一步
  147. const lastChecker = returnParams.processCheckers[returnParams.processCheckers.length - 1]
  148. if (username == lastChecker.v_user && 0 !== lastChecker.n_state) {
  149. //流程流转到当前用户且流程未撤销
  150. tinsId = lastChecker.l_tins_id
  151. }
  152. handleToProcessDetail({ username, insId, tinsId, insName, control })
  153. })
  154. }
  155. const staffId = userStore.user.useId
  156. const unitId = userStore.user.unitId
  157. getProcessList(staffId, unitId).then(res => {
  158. flowList.value = res.returnParams // 设置flowList
  159. // 先加载完流程列表数据,再获取待办流程数量
  160. // 使用 setTimeout 确保流程列表先显示
  161. setTimeout(() => {
  162. getProcessCountsByType()
  163. }, 500) // 延迟500毫秒调用,确保流程列表数据先加载
  164. })
  165. })
  166. // 搜索项
  167. const candidates = ref(['发起者', '类型', '时间'])
  168. // 搜索栏选中项
  169. const searchItem = ref(0)
  170. // 搜索项弹出层
  171. const searchItemPopup = ref(null)
  172. // 待办流程数量按类型分组
  173. const processCountsByType = ref({})
  174. // 待办流程数量按模型分组
  175. const processCountsByModel = ref({})
  176. // 打开搜索项弹出层
  177. function openPopup() {
  178. searchItemPopup.value.open()
  179. }
  180. // 关闭搜索项弹出层
  181. function closePopup() {
  182. searchItemPopup.value.close()
  183. }
  184. // 选中搜索项
  185. function clickSearchItem(item) {
  186. debugger
  187. // searchItem.value = item
  188. // if (item == 1 && pickerItems.value.length == 1) initPickerItems()
  189. if(item == "createUser") {
  190. } else if(item == "createTime") {
  191. } else {
  192. search(item.modelId)
  193. }
  194. closePopup()
  195. }
  196. // 搜索参数
  197. const queryParams = ref({})
  198. // 输入框搜索栏
  199. function searchBarConfirm(e) {
  200. // console.log('searchBarConfirm: ', e);
  201. }
  202. // 输入框搜索栏失去焦点
  203. function searchBarOnBlur(queryParam) {
  204. search(queryParam.value)
  205. }
  206. // 取消输入框搜索
  207. // function searchBarCancel() {
  208. // cancelSearch()
  209. // }
  210. // 下拉框搜索
  211. const pickerItems = ref([{ modelId: '', modelName: '无' }])
  212. const pickerItem = ref(0)
  213. // 流程列表
  214. const flowList = ref({
  215. fList: [],
  216. ftypeList: [
  217. {
  218. typeName: ''
  219. }
  220. ],
  221. })
  222. // 获取流程宫格数据
  223. function initPickerItems() {
  224. const staffId = userStore.user.useId
  225. const unitId = userStore.user.unitId
  226. getProcessList(staffId, unitId).then(res => {
  227. // flowList.value = res.returnParams // 设置flowList
  228. pickerItems.value = res.returnParams.fList.map(({ modelId, modelName }) => {
  229. return { modelId, modelName }
  230. })
  231. pickerItems.value.unshift({ modelId: '', modelName: '无' })
  232. })
  233. }
  234. // 搜索栏 下拉框选择项
  235. function bindPickerChange(e) {
  236. pickerItem.value = e.detail.value
  237. // console.log('bindPickerChange: ', e);
  238. }
  239. // 时间选择器搜索
  240. // const datetimePickerRange = ref([])
  241. function datetimePickerChange(event) {
  242. search(event)
  243. }
  244. // 搜索
  245. function searchByModelId(item) {
  246. queryParams.value = { 'modelId': item.modelId };
  247. processListRef.value.onClickItem() // 调用子组件刷新数据
  248. closePopup()
  249. }
  250. // 搜索
  251. function search(queryParam) {
  252. switch (searchItem.value) {
  253. case 0: queryParams.value = { 'name': queryParam }; break;
  254. case 1: queryParams.value = { 'modelId': queryParam }; break;
  255. case 2:
  256. queryParams.value = {
  257. 'starttime': queryParam[0],
  258. 'endtime': queryParam[1]
  259. };
  260. break;
  261. }
  262. // debugger
  263. // if(queryParam.value == "createUser") {
  264. // queryParams.value = { 'name': queryParam };
  265. // } else if(queryParam.value == "createTime") {
  266. // queryParams.value = {
  267. // 'starttime': queryParam[0],
  268. // 'endtime': queryParam[1]
  269. // };
  270. // } else {
  271. // queryParams.value = { 'modelId': queryParam };
  272. // }
  273. processListRef.value.onClickItem() // 调用子组件刷新数据
  274. }
  275. // 取消搜索
  276. function cancelSearch() {
  277. queryParams.value = {}
  278. processListRef.value.onClickItem() // 调用子组件刷新数据
  279. }
  280. // 获取待办流程数量并按类型分组
  281. function getProcessCountsByType() {
  282. const params = {
  283. staffId: userStore.user.useId,
  284. page: 1,
  285. pageNum: 9999, // 获取所有待办流程
  286. modelId: "",
  287. control: 1,
  288. queryParams: {}
  289. }
  290. getUserProcess(params).then(({ returnParams }) => {
  291. const processList2 = returnParams.list || []
  292. // 初始化计数器
  293. const countsByType = {}
  294. const countsByModel = {}
  295. // 遍历流程列表,按typeId和modelId统计数量
  296. processList2.forEach(process => {
  297. // 根据process.modelId与flowList.value.fList中的item.modelId进行匹配
  298. const matchingFlow = flowList.value.fList.find(f => f.modelId === process.modelId)
  299. if (matchingFlow && matchingFlow.typeId) {
  300. const typeId = matchingFlow.typeId.typeId
  301. // 按typeId统计
  302. countsByType[typeId] = (countsByType[typeId] || 0) + 1
  303. // 按modelId统计
  304. countsByModel[process.modelId] = (countsByModel[process.modelId] || 0) + 1
  305. }
  306. })
  307. // 更新响应式数据
  308. processCountsByType.value = countsByType
  309. processCountsByModel.value = countsByModel
  310. }).catch(error => {
  311. console.error('获取待办流程数量失败:', error)
  312. })
  313. }
  314. // 根据typeId获取待办数量
  315. function getTypeItemCount(typeId) {
  316. return processCountsByType.value[typeId] || 0
  317. }
  318. // 根据modelId获取待办数量
  319. function getModelItemCount(modelId) {
  320. return processCountsByModel.value[modelId] || 0
  321. }
  322. // 分段器选项
  323. const items = reactive(['我的', '抄送', '待办', '在办', '办结'])
  324. // 分段器选项
  325. const current = ref(items.findIndex(item => item == '待办'))
  326. // 子组件
  327. const processListRef = ref(null)
  328. // 待办列表
  329. // const processes = ref([])
  330. // 分段器点击事件 调用子组件刷新数据
  331. function clickSegmentItem({ currentIndex }) {
  332. // processes.value = [] // 清空列表数据
  333. current.value = currentIndex // 更新分段器状态
  334. processListRef.value.onClickItem() // 调用子组件刷新数据
  335. }
  336. // 获取待办列表数据
  337. const point = ref(0)
  338. const requestMap = [
  339. getUserAllProcess, // 我的
  340. getUserCopyProcess, // 抄送
  341. getUserProcess, // 待办
  342. getUserProcessing, // 在办
  343. getUserProcessed // 办结
  344. ]
  345. function getProcessData({ pageNo, pSize }, callback) {
  346. const flag = point.value = new Date().getTime()
  347. const params = {
  348. staffId: userStore.user.useId,
  349. page: pageNo,
  350. pageNum: pSize,
  351. modelId: "",
  352. control: 1,
  353. queryParams: queryParams.value
  354. }
  355. requestMap[current.value](params).then(( { returnParams, Rows, Total } ) => {
  356. // 只加载最新数据 防止快速连续点击分段器造成数据错乱
  357. if (flag == point.value) {
  358. callback(
  359. current.value == 1 ? Rows : returnParams.list,
  360. current.value == 1 ? Total : returnParams.total,
  361. pageNo
  362. )
  363. }
  364. })
  365. }
  366. // 分页获取待办列表数据
  367. function getProcessPage({ pageNo, pSize }, callback) {
  368. const params = {
  369. staffId: userStore.user.useId,
  370. page: pageNo,
  371. pageNum: pSize,
  372. modelId: "",
  373. control: 1,
  374. queryParams: queryParams.value
  375. }
  376. requestMap[current.value](params).then(( { returnParams, Rows, Total } ) => {
  377. callback(
  378. current.value == 1 ? Rows : returnParams.list,
  379. current.value == 1 ? Total : returnParams.total,
  380. pageNo
  381. )
  382. })
  383. }
  384. // 跳转到流程详情页
  385. function handleToProcessDetail({ username, insId, tinsId, insName, control }) {
  386. debugger
  387. let url = '/pages/process/detail/index?insId=' + insId + '&insName=' + insName + '&control=' + control
  388. if (tinsId && current.value != 1) { // 排除抄送流程的tinsId
  389. url = url + '&tinsId=' + tinsId
  390. }
  391. // console.log('url', url)
  392. $tab.navigateTo(url)
  393. }
  394. function handleToCancelProcess(process) {
  395. uni.showModal({
  396. title: '确认撤回' + process.insName,
  397. editable: true,
  398. placeholderText: '请输入撤回备注',
  399. success: ({ confirm, content }) => {
  400. if (content == '') {
  401. $modal.msgError('撤回备注不能为空!')
  402. return
  403. }
  404. if (confirm) {
  405. cancelProcessFlow(userStore.user.useId, content, process)
  406. .then(({ returnMsg }) => {
  407. if (returnMsg.includes('success')) {
  408. $modal.msgSuccess('撤销成功')
  409. // 通知列表刷新数据
  410. processListRef.value.onClickItem() // 调用子组件刷新数据
  411. } else {
  412. $modal.msgError(returnMsg)
  413. }
  414. })
  415. }
  416. }
  417. })
  418. }
  419. </script>
  420. <style lang="scss" scoped>
  421. ::v-deep .uni-badge {
  422. height: calc(1.5rem + 0px) !important;
  423. min-width: calc(1.5rem + 0px) !important;
  424. line-height: calc(1.375rem + 0px) !important;
  425. font-size: calc(1.125rem + 0px) !important;
  426. }
  427. // @import url("@/static/font/ygoa/iconfont.css");
  428. .search_container {
  429. padding: 10px 0;
  430. .popup_button_container {
  431. display: flex;
  432. justify-content: center;
  433. margin-left: 5px;
  434. height: 36px;
  435. line-height: 36px;
  436. width: 100%;
  437. background-color: #f5f5f5;
  438. text-align: center;
  439. font-size: calc(16px + .5*(1rem - 16px));
  440. color: #333;
  441. .ygoa_icon {
  442. font-size: calc(16px + .5*(1rem - 16px));
  443. }
  444. .button_text {
  445. font-size: calc(16px + .5*(1rem - 16px));
  446. width: 64px;
  447. margin-left: 4px;
  448. }
  449. }
  450. .clear_button_container {
  451. display: flex;
  452. justify-content: center;
  453. margin-left: 5px;
  454. height: 36px;
  455. line-height: 36px;
  456. width: 100%;
  457. background-color: #f5f5f5;
  458. text-align: center;
  459. color: #999;
  460. &:active {
  461. background-color: #e0e0e0;
  462. }
  463. }
  464. ::v-deep .search_bar {
  465. .uni-searchbar {
  466. padding: 0;
  467. .uni-searchbar__box-search-input {
  468. font-size: calc(14px + .5*(1rem - 16px)) !important;
  469. }
  470. .uni-searchbar__cancel {
  471. font-size: calc(14px + .5*(1rem - 16px)) !important;
  472. }
  473. }
  474. .picker_container {
  475. display: inline-block;
  476. float: left;
  477. background-color: #f8f8f8;
  478. width: 70%;
  479. height: 36px;
  480. .input_text {
  481. display: flex;
  482. justify-content: center;
  483. text-align: center;
  484. background-color: #f8f8f8;
  485. border: 1px solid #e5e5e5;
  486. border-radius: 5px;
  487. width: 100%;
  488. height: 26px;
  489. color: #000;
  490. font-size: calc(14px + .5*(1rem - 16px)) !important;
  491. line-height: 26px;
  492. padding: 4px 8px 4px 0;
  493. }
  494. }
  495. .picker_button_container {
  496. display: inline-flex;
  497. justify-content: center;
  498. margin-left: 5px;
  499. height: 36px;
  500. line-height: 36px;
  501. background-color: #f5f5f5;
  502. text-align: center;
  503. font-size: calc(16px + .5*(1rem - 16px));
  504. width: 25%;
  505. .button_text {
  506. overflow: hidden;
  507. font-size: calc(16px + .5*(1rem - 16px));
  508. margin-left: 4px;
  509. }
  510. }
  511. .datetime_picker_container {
  512. .uni-date {
  513. .uni-date-editor {
  514. margin-right: 5px;
  515. .uni-date-x {
  516. background-color: #f8f8f8;
  517. color: #000;
  518. font-size: calc(14px + .5*(1rem - 16px));
  519. .uni-icons {
  520. font-size: calc(22px + .5*(1rem - 16px));
  521. }
  522. .uni-date__x-input {
  523. font-size: calc(14px + .5*(1rem - 16px));
  524. }
  525. }
  526. .uni-date__icon-clear {
  527. .uni-icons {
  528. font-size: calc(22px + .5*(1rem - 16px));
  529. // color: #c0c4cc;
  530. }
  531. }
  532. }
  533. }
  534. }
  535. }
  536. }
  537. ::v-deep .segmented_control_container {
  538. .segmented-control__text {
  539. font-size: calc(14px + .5*(1rem - 16px));
  540. }
  541. }
  542. ::v-deep .process_list {
  543. .process_contant {
  544. font-size: calc(14px + .5*(1rem - 16px));
  545. .button_container {
  546. button {
  547. font-size: calc(13px + .4*(1rem - 16px))
  548. }
  549. }
  550. }
  551. .zp-l-text-rpx {
  552. font-size: calc(30rpx + .5*(1rem - 16px));
  553. }
  554. .flow_step_section {
  555. .uni-section .uni-section-header {
  556. padding: 5px 10px;
  557. }
  558. }
  559. .flow_step_container {
  560. min-height: 60px;
  561. margin: 10px 15px;
  562. .u-steps {
  563. .u-steps-item {
  564. padding-bottom: 11px;
  565. .u-text__value--content {
  566. font-size: calc(13px + .5*(1rem - 16px)) !important;
  567. }
  568. .u-text__value--main {
  569. font-size: calc(13px + .5*(1rem - 16px)) !important;
  570. font-weight: 500 !important;
  571. }
  572. .u-text__value--tips {
  573. font-size: calc(12px + .5*(1rem - 16px)) !important;
  574. }
  575. .redcontent {
  576. .u-text__value--content {
  577. color: #ff4500;
  578. }
  579. }
  580. .active_step_circle {
  581. width: 20px;
  582. height: 20px;
  583. box-sizing: border-box;
  584. flex-shrink: 0;
  585. border-radius: 100px;
  586. border-width: 1px;
  587. border-color: #A78BFA;
  588. background-color: #A78BFA;
  589. border-style: solid;
  590. display: flex;
  591. flex-direction: row;
  592. align-items: center;
  593. justify-content: center;
  594. transition: background-color .3s;
  595. .active_step_text {
  596. color: #fff;
  597. font-size: 11px;
  598. display: flex;
  599. flex-direction: row;
  600. align-items: center;
  601. justify-content: center;
  602. text-align: center;
  603. line-height: 11px;
  604. }
  605. }
  606. }
  607. .u-steps-item view:last-of-type {
  608. margin-top: 0 !important;
  609. }
  610. }
  611. }
  612. }
  613. ::v-deep .uni-calendar__content {
  614. margin: -20px;
  615. margin-top: 20px;
  616. .uni-calendar__header {
  617. .uni-calendar__header-text {
  618. font-size: calc(14px + .5*(1rem - 16px)) !important;
  619. }
  620. .uni-calendar__backtoday {
  621. padding: 2px 8px 2px 10px !important;
  622. font-size: calc(0.75rem + 0px) !important;
  623. }
  624. }
  625. .uni-calendar__box {
  626. .uni-calendar__weeks {
  627. .uni-calendar__weeks-day {
  628. .uni-calendar__weeks-day-text {
  629. font-size: calc(14px + .5*(1rem - 16px)) !important;
  630. }
  631. }
  632. .uni-calendar__weeks-item {
  633. .uni-calendar-item__weeks-box-item {
  634. .uni-calendar-item__weeks-box-circle {
  635. width: calc(8px + .5*(1rem - 16px)) !important;
  636. height: calc(8px + .5*(1rem - 16px)) !important;
  637. top: calc(5px - .25*(1rem - 16px)) !important;
  638. right: calc(5px - .25*(1rem - 16px)) !important;
  639. }
  640. .uni-calendar-item__weeks-box-text {
  641. font-size: calc(14px + .5*(1rem - 16px)) !important;
  642. }
  643. .uni-calendar-item__weeks-lunar-text {
  644. font-size: calc(12px + .5*(1rem - 16px)) !important;
  645. }
  646. }
  647. }
  648. }
  649. }
  650. .uni-date-changed {
  651. .uni-date-changed--time-date {
  652. font-size: calc(14px + 1*(1rem - 16px)) !important;
  653. }
  654. .uni-datetime-picker-text {
  655. font-size: calc(14px + 1*(1rem - 16px)) !important;
  656. }
  657. }
  658. }
  659. /* 弹窗整体样式 */
  660. .popup_container {
  661. // min-height: 1000rpx;
  662. ::v-deep .uni-popup__content {
  663. border-radius: 16rpx 16rpx 0 0;
  664. background-color: #fff;
  665. }
  666. }
  667. /* 弹窗标题 */
  668. .popup-title {
  669. font-size: 32rpx;
  670. font-weight: bold;
  671. padding: 20rpx 30rpx;
  672. border-bottom: 1px solid #f5f5f7;
  673. color: #333;
  674. }
  675. /* 流程分类列表容器 */
  676. .flow-category-list {
  677. ::v-deep .uni-list {
  678. background: #fff;
  679. border: none;
  680. }
  681. }
  682. /* 一级分类:流程类型组样式 */
  683. .flow-type-group {
  684. ::v-deep .uni-collapse-item__content {
  685. padding: 0;
  686. border: none;
  687. }
  688. .group-header {
  689. display: flex;
  690. align-items: center;
  691. padding: 20rpx 30rpx;
  692. width: 100%;
  693. box-sizing: border-box;
  694. .group-icon {
  695. margin-right: 16rpx;
  696. color: #666;
  697. }
  698. .group-name {
  699. font-size: 28rpx;
  700. flex: 1;
  701. color: #333;
  702. }
  703. .group-arrow {
  704. color: #999;
  705. margin-left: 10rpx;
  706. }
  707. }
  708. }
  709. /* 二级分类:流程项样式 */
  710. .flow-item-sub {
  711. ::v-deep .uni-list-item__container {
  712. padding: 16rpx 60rpx; /* 缩进显示,区分一级分类 */
  713. border: none;
  714. // 点击时的高亮效果(可选)
  715. &:active {
  716. background-color: #F0F0F0; // 点击时加深一点,提升交互体验
  717. }
  718. }
  719. .sub-item-title {
  720. display: flex;
  721. justify-content: space-between;
  722. align-items: center;
  723. font-size: 26rpx;
  724. color: #666;
  725. width: 100%;
  726. box-sizing: border-box;
  727. }
  728. }
  729. /* 通用角标样式 */
  730. .badge {
  731. min-width: 36rpx;
  732. height: 36rpx;
  733. line-height: 36rpx;
  734. text-align: center;
  735. background-color: #ff4d4f;
  736. color: #fff;
  737. font-size: 22rpx;
  738. border-radius: 18rpx;
  739. padding: 0 8rpx;
  740. margin-right: 10rpx;
  741. display: inline-block !important;
  742. }
  743. /* 小角标(单个流程项使用,可选) */
  744. .small-badge {
  745. min-width: 30rpx;
  746. height: 30rpx;
  747. line-height: 30rpx;
  748. font-size: 20rpx;
  749. display: inline-block !important;
  750. }
  751. ::v-deep .uni-section {
  752. overflow-y: scroll;
  753. max-height: 1000rpx;
  754. min-height: 1000rpx;
  755. background-color: #fff;
  756. }
  757. // 给 uni-list-item 加相对定位,约束 right 插槽
  758. ::v-deep .uni-list-item {
  759. position: relative !important; // 关键:约束绝对定位的 right 插槽
  760. width: 100% !important; // 确保列表项占满父容器
  761. box-sizing: border-box !important;
  762. }
  763. // 调整 uni-badge 样式,避免溢出
  764. ::v-deep .uni-badge {
  765. position: static !important; // 取消绝对定位,改为静态流布局
  766. margin-left: 10rpx !important; // 与文字保持间距
  767. display: inline-block !important;
  768. background-color: #ff4d4f !important;
  769. }
  770. </style>