index.vue 13 KB

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