index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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="6" :sm="4">
  7. <view @click="openPopup" class="popup_button_container">
  8. <text class="ygoa_icon icon-filter"></text>
  9. <text class="button_text">{{ candidates[searchItem] }}</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="18" :sm="20">
  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="18" :sm="20">
  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. </view>
  43. </uni-row>
  44. </view>
  45. <view class="segmented_control_container">
  46. <uni-segmented-control :current="current" :values="items" @clickItem="clickSegmentItem" styleType="text"
  47. activeColor="#409eff"></uni-segmented-control>
  48. </view>
  49. <view class="process_list">
  50. <process-list ref="processListRef" @clickCancel="handleToCancelProcess" @clickSegment="getProcessData"
  51. @clickItem="handleToProcessDetail" @scrollToBottom="getProcessPage" :current="current" :pSize="5"
  52. :pageNo="1"></process-list>
  53. </view>
  54. <view class="popup_container">
  55. <uni-popup ref="searchItemPopup" type="bottom">
  56. <uni-list>
  57. <uni-list-item @click="clickSearchItem(index)" v-for="(item, index) in candidates" :key="index"
  58. clickable :title="item">
  59. </uni-list-item>
  60. </uni-list>
  61. </uni-popup>
  62. </view>
  63. </view>
  64. </template>
  65. <script setup lang="ts">
  66. import processList from '@/components/ygoa/processList.vue'
  67. import { onShow, onLoad } from '@dcloudio/uni-app'
  68. import { reactive, ref, onMounted } from 'vue';
  69. import $tab from '@/plugins/tab.js'
  70. import $modal from '@/plugins/modal.js'
  71. import { getUserProcess, getUserProcessed, getUserProcessing, getUserAllProcess, getUserCopyProcess, cancelProcessFlow, getProcessList, getProcessFormInfo } from '@/api/process';
  72. import { useUserStore } from '@/store/user';
  73. onMounted(() => {
  74. uni.$on('ReloadProcessData', () => {
  75. new Promise((resolve, reject) => {
  76. processListRef.value.onClickItem()
  77. })
  78. })
  79. })
  80. onShow(() => {
  81. uni.$emit('showTabBarBadge')
  82. })
  83. const userStore = useUserStore()
  84. onLoad(({ insId, tinsId, insName, control }) => {
  85. if (insId) {
  86. const username = userStore.user.name
  87. getProcessFormInfo( userStore.user.useId, insId ).then(({ returnParams }) => {
  88. //流程流转的最后一步
  89. const lastChecker = returnParams.processCheckers[returnParams.processCheckers.length - 1]
  90. if (username == lastChecker.v_user && 0 !== lastChecker.n_state) {
  91. //流程流转到当前用户且流程未撤销
  92. tinsId = lastChecker.l_tins_id
  93. }
  94. handleToProcessDetail({ username, insId, tinsId, insName, control })
  95. })
  96. }
  97. })
  98. // 搜索项
  99. const candidates = ref(['发起者', '类型', '时间'])
  100. // 搜索栏选中项
  101. const searchItem = ref(0)
  102. // 搜索项弹出层
  103. const searchItemPopup = ref(null)
  104. // 打开搜索项弹出层
  105. function openPopup() {
  106. searchItemPopup.value.open()
  107. }
  108. // 关闭搜索项弹出层
  109. function closePopup() {
  110. searchItemPopup.value.close()
  111. }
  112. // 选中搜索项
  113. function clickSearchItem(item) {
  114. searchItem.value = item
  115. if (item == 1 && pickerItems.value.length == 1) initPickerItems()
  116. closePopup()
  117. }
  118. // 搜索参数
  119. const queryParams = ref({})
  120. // 输入框搜索栏
  121. function searchBarConfirm(e) {
  122. // console.log('searchBarConfirm: ', e);
  123. }
  124. // 输入框搜索栏失去焦点
  125. function searchBarOnBlur(queryParam) {
  126. search(queryParam.value)
  127. }
  128. // 取消输入框搜索
  129. // function searchBarCancel() {
  130. // cancelSearch()
  131. // }
  132. // 下拉框搜索
  133. const pickerItems = ref([{ modelId: '', modelName: '无' }])
  134. const pickerItem = ref(0)
  135. // 获取流程宫格数据
  136. function initPickerItems() {
  137. const staffId = userStore.user.useId
  138. const unitId = userStore.user.unitId
  139. getProcessList(staffId, unitId).then(res => {
  140. pickerItems.value = res.returnParams.fList.map(({ modelId, modelName }) => {
  141. return { modelId, modelName }
  142. })
  143. pickerItems.value.unshift({ modelId: '', modelName: '无' })
  144. })
  145. }
  146. // 搜索栏 下拉框选择项
  147. function bindPickerChange(e) {
  148. pickerItem.value = e.detail.value
  149. // console.log('bindPickerChange: ', e);
  150. }
  151. // 时间选择器搜索
  152. // const datetimePickerRange = ref([])
  153. function datetimePickerChange(event) {
  154. search(event)
  155. }
  156. // 搜索
  157. function search(queryParam) {
  158. switch (searchItem.value) {
  159. case 0: queryParams.value = { 'name': queryParam }; break;
  160. case 1: queryParams.value = { 'modelId': queryParam }; break;
  161. case 2:
  162. queryParams.value = {
  163. 'starttime': queryParam[0],
  164. 'endtime': queryParam[1]
  165. };
  166. break;
  167. }
  168. processListRef.value.onClickItem() // 调用子组件刷新数据
  169. }
  170. // 取消搜索
  171. function cancelSearch() {
  172. queryParams.value = {}
  173. processListRef.value.onClickItem() // 调用子组件刷新数据
  174. }
  175. // 分段器选项
  176. const items = reactive(['我的', '抄送', '待办', '在办', '办结'])
  177. // 分段器选项
  178. const current = ref(items.findIndex(item => item == '待办'))
  179. // 子组件
  180. const processListRef = ref(null)
  181. // 待办列表
  182. // const processes = ref([])
  183. // 分段器点击事件 调用子组件刷新数据
  184. function clickSegmentItem({ currentIndex }) {
  185. // processes.value = [] // 清空列表数据
  186. current.value = currentIndex // 更新分段器状态
  187. processListRef.value.onClickItem() // 调用子组件刷新数据
  188. }
  189. // 获取待办列表数据
  190. const point = ref(0)
  191. const requestMap = [
  192. getUserAllProcess, // 我的
  193. getUserCopyProcess, // 抄送
  194. getUserProcess, // 待办
  195. getUserProcessing, // 在办
  196. getUserProcessed // 办结
  197. ]
  198. function getProcessData({ pageNo, pSize }, callback) {
  199. const flag = point.value = new Date().getTime()
  200. const params = {
  201. staffId: userStore.user.useId,
  202. page: pageNo,
  203. pageNum: pSize,
  204. modelId: "",
  205. control: 1,
  206. queryParams: queryParams.value
  207. }
  208. requestMap[current.value](params).then(( { returnParams, Rows, Total } ) => {
  209. // 只加载最新数据 防止快速连续点击分段器造成数据错乱
  210. if (flag == point.value) {
  211. callback(
  212. current.value == 1 ? Rows : returnParams.list,
  213. current.value == 1 ? Total : returnParams.total,
  214. pageNo
  215. )
  216. }
  217. })
  218. }
  219. // 分页获取待办列表数据
  220. function getProcessPage({ pageNo, pSize }, callback) {
  221. const params = {
  222. staffId: userStore.user.useId,
  223. page: pageNo,
  224. pageNum: pSize,
  225. modelId: "",
  226. control: 1,
  227. queryParams: queryParams.value
  228. }
  229. requestMap[current.value](params).then(( { returnParams, Rows, Total } ) => {
  230. callback(
  231. current.value == 1 ? Rows : returnParams.list,
  232. current.value == 1 ? Total : returnParams.total,
  233. pageNo
  234. )
  235. })
  236. }
  237. // 跳转到流程详情页
  238. function handleToProcessDetail({ username, insId, tinsId, insName, control }) {
  239. let url = '/pages/process/detail/index?insId=' + insId + '&insName=' + insName + '&control=' + control
  240. if (tinsId && current.value != 1) { // 排除抄送流程的tinsId
  241. url = url + '&tinsId=' + tinsId
  242. }
  243. // console.log('url', url)
  244. $tab.navigateTo(url)
  245. }
  246. function handleToCancelProcess(process) {
  247. uni.showModal({
  248. title: '确认撤回' + process.insName,
  249. editable: true,
  250. placeholderText: '请输入撤回备注',
  251. success: ({ confirm, content }) => {
  252. if (content == '') {
  253. $modal.msgError('撤回备注不能为空!')
  254. return
  255. }
  256. if (confirm) {
  257. cancelProcessFlow(userStore.user.useId, content, process)
  258. .then(({ returnMsg }) => {
  259. if (returnMsg.includes('success')) {
  260. $modal.msgSuccess('撤销成功')
  261. // 通知列表刷新数据
  262. processListRef.value.onClickItem() // 调用子组件刷新数据
  263. } else {
  264. $modal.msgError(returnMsg)
  265. }
  266. })
  267. }
  268. }
  269. })
  270. }
  271. </script>
  272. <style lang="scss" scoped>
  273. // @import url("@/static/font/ygoa/iconfont.css");
  274. .search_container {
  275. padding: 10px 0;
  276. .popup_button_container {
  277. display: flex;
  278. justify-content: center;
  279. margin-left: 5px;
  280. height: 36px;
  281. line-height: 36px;
  282. width: 100%;
  283. background-color: #f5f5f5;
  284. text-align: center;
  285. font-size: calc(16px + .5*(1rem - 16px));
  286. color: #333;
  287. .ygoa_icon {
  288. font-size: calc(16px + .5*(1rem - 16px));
  289. }
  290. .button_text {
  291. font-size: calc(16px + .5*(1rem - 16px));
  292. width: 64px;
  293. margin-left: 4px;
  294. }
  295. }
  296. ::v-deep .search_bar {
  297. .uni-searchbar {
  298. padding: 0;
  299. .uni-searchbar__box-search-input {
  300. font-size: calc(14px + .5*(1rem - 16px)) !important;
  301. }
  302. .uni-searchbar__cancel {
  303. font-size: calc(14px + .5*(1rem - 16px)) !important;
  304. }
  305. }
  306. .picker_container {
  307. display: inline-block;
  308. float: left;
  309. background-color: #f8f8f8;
  310. width: 70%;
  311. height: 36px;
  312. .input_text {
  313. display: flex;
  314. justify-content: center;
  315. text-align: center;
  316. background-color: #f8f8f8;
  317. border: 1px solid #e5e5e5;
  318. border-radius: 5px;
  319. width: 100%;
  320. height: 26px;
  321. color: #000;
  322. font-size: calc(14px + .5*(1rem - 16px)) !important;
  323. line-height: 26px;
  324. padding: 4px 8px 4px 0;
  325. }
  326. }
  327. .picker_button_container {
  328. display: inline-flex;
  329. justify-content: center;
  330. margin-left: 5px;
  331. height: 36px;
  332. line-height: 36px;
  333. background-color: #f5f5f5;
  334. text-align: center;
  335. font-size: calc(16px + .5*(1rem - 16px));
  336. width: 25%;
  337. .button_text {
  338. overflow: hidden;
  339. font-size: calc(16px + .5*(1rem - 16px));
  340. margin-left: 4px;
  341. }
  342. }
  343. .datetime_picker_container {
  344. .uni-date {
  345. .uni-date-editor {
  346. margin-right: 5px;
  347. .uni-date-x {
  348. background-color: #f8f8f8;
  349. color: #000;
  350. font-size: calc(14px + .5*(1rem - 16px));
  351. .uni-icons {
  352. font-size: calc(22px + .5*(1rem - 16px));
  353. }
  354. .uni-date__x-input {
  355. font-size: calc(14px + .5*(1rem - 16px));
  356. }
  357. }
  358. .uni-date__icon-clear {
  359. .uni-icons {
  360. font-size: calc(22px + .5*(1rem - 16px));
  361. // color: #c0c4cc;
  362. }
  363. }
  364. }
  365. }
  366. }
  367. }
  368. }
  369. ::v-deep .segmented_control_container {
  370. .segmented-control__text {
  371. font-size: calc(14px + .5*(1rem - 16px));
  372. }
  373. }
  374. ::v-deep .process_list {
  375. .process_contant {
  376. font-size: calc(14px + .5*(1rem - 16px));
  377. .button_container {
  378. button {
  379. font-size: calc(13px + .4*(1rem - 16px))
  380. }
  381. }
  382. }
  383. .zp-l-text-rpx {
  384. font-size: calc(30rpx + .5*(1rem - 16px));
  385. }
  386. .flow_step_section {
  387. .uni-section .uni-section-header {
  388. padding: 5px 10px;
  389. }
  390. }
  391. .flow_step_container {
  392. min-height: 60px;
  393. margin: 10px 15px;
  394. .u-steps {
  395. .u-steps-item {
  396. padding-bottom: 11px;
  397. .u-text__value--content {
  398. font-size: calc(13px + .5*(1rem - 16px)) !important;
  399. }
  400. .u-text__value--main {
  401. font-size: calc(13px + .5*(1rem - 16px)) !important;
  402. font-weight: 500 !important;
  403. }
  404. .u-text__value--tips {
  405. font-size: calc(12px + .5*(1rem - 16px)) !important;
  406. }
  407. .redcontent {
  408. .u-text__value--content {
  409. color: #ff4500;
  410. }
  411. }
  412. .active_step_circle {
  413. width: 20px;
  414. height: 20px;
  415. box-sizing: border-box;
  416. flex-shrink: 0;
  417. border-radius: 100px;
  418. border-width: 1px;
  419. border-color: #A78BFA;
  420. background-color: #A78BFA;
  421. border-style: solid;
  422. display: flex;
  423. flex-direction: row;
  424. align-items: center;
  425. justify-content: center;
  426. transition: background-color .3s;
  427. .active_step_text {
  428. color: #fff;
  429. font-size: 11px;
  430. display: flex;
  431. flex-direction: row;
  432. align-items: center;
  433. justify-content: center;
  434. text-align: center;
  435. line-height: 11px;
  436. }
  437. }
  438. }
  439. .u-steps-item view:last-of-type {
  440. margin-top: 0 !important;
  441. }
  442. }
  443. }
  444. }
  445. ::v-deep .uni-calendar__content {
  446. margin: -20px;
  447. margin-top: 20px;
  448. .uni-calendar__header {
  449. .uni-calendar__header-text {
  450. font-size: calc(14px + .5*(1rem - 16px)) !important;
  451. }
  452. .uni-calendar__backtoday {
  453. padding: 2px 8px 2px 10px !important;
  454. font-size: calc(0.75rem + 0px) !important;
  455. }
  456. }
  457. .uni-calendar__box {
  458. .uni-calendar__weeks {
  459. .uni-calendar__weeks-day {
  460. .uni-calendar__weeks-day-text {
  461. font-size: calc(14px + .5*(1rem - 16px)) !important;
  462. }
  463. }
  464. .uni-calendar__weeks-item {
  465. .uni-calendar-item__weeks-box-item {
  466. .uni-calendar-item__weeks-box-circle {
  467. width: calc(8px + .5*(1rem - 16px)) !important;
  468. height: calc(8px + .5*(1rem - 16px)) !important;
  469. top: calc(5px - .25*(1rem - 16px)) !important;
  470. right: calc(5px - .25*(1rem - 16px)) !important;
  471. }
  472. .uni-calendar-item__weeks-box-text {
  473. font-size: calc(14px + .5*(1rem - 16px)) !important;
  474. }
  475. .uni-calendar-item__weeks-lunar-text {
  476. font-size: calc(12px + .5*(1rem - 16px)) !important;
  477. }
  478. }
  479. }
  480. }
  481. }
  482. .uni-date-changed {
  483. .uni-date-changed--time-date {
  484. font-size: calc(14px + 1*(1rem - 16px)) !important;
  485. }
  486. .uni-datetime-picker-text {
  487. font-size: calc(14px + 1*(1rem - 16px)) !important;
  488. }
  489. }
  490. }
  491. </style>