index.vue 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. <template>
  2. <view class="dynamicModel-list-v">
  3. <!-- 批量删除顶部弹窗 -->
  4. <view class="u-flex top-btn" :class="slide2" v-show="showTop">
  5. <view class="button-left" @click.stop="cancel">
  6. <p class="u-m-t-10 u-font-28">{{$t('common.cancelText')}}</p>
  7. </view>
  8. <view class="button-center">
  9. <p class="u-m-t-10 u-font-28">已选中{{selectItems.length}}条</p>
  10. </view>
  11. <view class="button-right u-m-t-12" @click.stop="checkAll">
  12. <p class="icon-ym icon-ym-app-checkAll " :style="{'color':this.checkedAll ? '#0293fc' : '#303133'}">
  13. </p>
  14. </view>
  15. </view>
  16. <!-- 排序 -->
  17. <view class="head-warp com-dropdown">
  18. <u-dropdown class="u-dropdown" ref="uDropdown">
  19. <u-dropdown-item :title="$t('app.apply.sort')" :options="sortOptions">
  20. <view class="screen-box">
  21. <view class="screen-list" v-if="sortOptions.length">
  22. <view class="u-p-l-20 u-p-r-20 list">
  23. <scroll-view scroll-y="true" style="height: 100%;">
  24. <u-cell-group :border="false">
  25. <u-cell-item @click="cellClick(item)" :arrow="false" :title="item.label"
  26. v-for="(item, index) in sortOptions" :key="index" :title-style="{
  27. color: sortValue.includes(item.value) ? '#2979ff' : '#606266' }">
  28. <u-icon v-if="sortValue.includes(item.value)" name="checkbox-mark"
  29. color="#2979ff" size="32" />
  30. </u-cell-item>
  31. </u-cell-group>
  32. </scroll-view>
  33. </view>
  34. </view>
  35. <view v-else class="notData-box u-flex-col">
  36. <view class="u-flex-col notData-inner">
  37. <image :src="icon" class="iconImg"></image>
  38. <text class="notData-inner-text">{{$t('common.noData')}}</text>
  39. </view>
  40. </view>
  41. <view class="buttom-actions" v-if="sortOptions.length">
  42. <u-button class="buttom-btn" @click="handleSortReset">{{$t('common.cleanText')}}</u-button>
  43. <u-button class="buttom-btn" type="primary" @click="handleSortSearch">
  44. {{$t('common.okText')}}
  45. </u-button>
  46. </view>
  47. </view>
  48. </u-dropdown-item>
  49. <!-- 筛选 -->
  50. <u-dropdown-item :title="$t('app.apply.screen')">
  51. <view class="screen-box u-flex-col">
  52. <view class="screen-list" v-if="showParser && searchFormConf.length">
  53. <view class="u-p-l-20 u-p-r-20 list">
  54. <scroll-view scroll-y="true" style="height: 100%;">
  55. <Parser :formConf="searchFormConf" :searchFormData="searchFormData"
  56. :webType="config.webType" ref="searchForm" @submit="sumbitSearchForm" />
  57. </scroll-view>
  58. </view>
  59. <view class="u-flex screen-btn" v-if="showParser && searchFormConf.length">
  60. <text @click="handleReset" class="btn btn1">{{$t('common.resetText')}}</text>
  61. <text @click="handleSearch" class="btn btn2">{{$t('common.searchText')}}</text>
  62. </view>
  63. </view>
  64. <view v-else class="notData-box u-flex-col">
  65. <view class="u-flex-col notData-inner">
  66. <image :src="icon" class="iconImg"></image>
  67. <text class="notData-inner-text">{{$t('common.noData')}}</text>
  68. </view>
  69. </view>
  70. </view>
  71. </u-dropdown-item>
  72. </u-dropdown>
  73. </view>
  74. <u-tabs :list="tabList" v-model="tabActiveKey" font-size="28" @change="onTabChange" height="80" name="fullName"
  75. v-show="showTabs">
  76. </u-tabs>
  77. <!-- 列表 -->
  78. <view class="list-warp">
  79. <mescroll-uni ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback"
  80. :down="downOption" :up="upOption" :bottombar="false"
  81. :top="(columnData.tabConfig && columnData.tabConfig.on && tabList.length) ? 170 : 80">
  82. <list ref="list" :list="list" :columnList="columnList" :config="config" :actionOptions="actionOptions"
  83. @relationFormClick="relationFormClick" @goDetail="goDetail" @handleMoreClick="handleMoreClick"
  84. @handleClick="handleClick" :showSelect="showTop" :checkedAll="checkedAll"
  85. @selectCheckbox="selectCheckbox" :isMoreBtn="isMoreBtn" :customBtnsList="columnData.customBtnsList">
  86. </list>
  87. </mescroll-uni>
  88. </view>
  89. <view v-if="!showTop">
  90. <!-- 新增按钮 -->
  91. <view v-if="config.webType !=4">
  92. <view class="com-addBtn"
  93. v-if="isPreview||(permission.btnPermission && permission.btnPermission.includes('btn_add'))"
  94. @click="addPage()">
  95. <u-icon name="plus" size="48" color="#fff" />
  96. </view>
  97. </view>
  98. <!-- 批量操作 -->
  99. <view class="com-batch" @click="openBatchOperate()" v-if="showBatchOperate">
  100. <u-icon name="grid" size="48" color="#848484" />
  101. </view>
  102. </view>
  103. <u-select :list="listInnerBtn" v-model="showMoreBtn" @confirm="selectBtnconfirm" />
  104. <u-select :list="bottomCustomBtnsList[1]" v-model="showBottomMoreBtn" @confirm="bottomBtnConfirm" />
  105. <!-- 批量操作底部弹窗 -->
  106. <view class="u-flex bottom-btn" :class="slide" v-show="selectItems.length">
  107. <view class="button-preIcon" @click.stop="handleBottomMoreClick('down')"
  108. v-if="bottomCustomBtnsList[1].length">
  109. <u-icon name="more-dot-fill" class="u-m-b-8" size="34"></u-icon>
  110. <p class="u-font-24">{{$t('common.moreText')}}</p>
  111. </view>
  112. <!-- 自定义按钮 -->
  113. <view class="button-preIcon" v-for="(item,i) in bottomCustomBtnsList[0]" :key="i"
  114. @click="bottomBtnConfirm(item)">
  115. <p class="btn-icon u-m-b-8" :class="item.event.btnIcon">
  116. </p>
  117. <p class="u-m-t-10 u-font-24 u-line-1">{{item.label}}</p>
  118. </view>
  119. <!-- 删除 -->
  120. <view class="button-preIcon" @click.stop="batchDelete" v-if="isBatchRemove">
  121. <p class="icon-ym icon-ym-app-delete u-m-b-8"></p>
  122. <p class="u-m-t-10 u-font-24">{{$t('common.delText')}}</p>
  123. </view>
  124. </view>
  125. </view>
  126. </template>
  127. <script>
  128. import {
  129. useBaseStore
  130. } from '@/store/modules/base'
  131. const baseStore = useBaseStore()
  132. import list from './list.vue'
  133. import resources from '@/libs/resources.js'
  134. import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
  135. import bulkOperationMixin from "../../bulkOperationMixin.js";
  136. import Parser from '../parser/index.vue'
  137. import {
  138. getModelList,
  139. deteleModel,
  140. getModelInfo,
  141. launchFlow
  142. } from '@/api/apply/visualDev'
  143. import {
  144. getDataInterfaceRes
  145. } from '@/api/common'
  146. import deepClone from '../../../../../uni_modules/vk-uview-ui/libs/function/deepClone';
  147. export default {
  148. mixins: [MescrollMixin, bulkOperationMixin],
  149. props: ['config', 'modelId', 'isPreview', 'title', 'menuId'],
  150. components: {
  151. Parser,
  152. list
  153. },
  154. data() {
  155. return {
  156. tabActiveKey: 0,
  157. tabList: [],
  158. tabQueryJson: {},
  159. sortValue: [],
  160. icon: resources.message.nodata,
  161. downOption: {
  162. use: true,
  163. auto: false
  164. },
  165. upOption: {
  166. page: {
  167. num: 0,
  168. size: 10,
  169. time: null
  170. },
  171. empty: {
  172. use: true,
  173. icon: resources.message.nodata,
  174. tip: this.$t('common.noData'),
  175. fixed: true
  176. },
  177. textNoMore: this.$t('app.apply.noMoreData'),
  178. },
  179. list: [],
  180. listQuery: {
  181. sidx: '',
  182. keyword: '',
  183. queryJson: ''
  184. },
  185. actionOptions: [],
  186. showParser: false,
  187. columnData: {},
  188. columnList: [],
  189. sortList: [],
  190. sortOptions: [],
  191. searchList: [],
  192. searchFormConf: [],
  193. permission: {},
  194. selectListIndex: 0,
  195. showBottomMoreBtn: false,
  196. showMoreBtn: false,
  197. properties: {},
  198. flowId: '',
  199. key: +new Date(),
  200. userInfo: {},
  201. searchFormData: {},
  202. enableFunc: {},
  203. selectItems: [],
  204. listInnerBtn: [],
  205. listTopBtn: []
  206. }
  207. },
  208. created() {
  209. this.init()
  210. },
  211. computed: {
  212. showBatchOperate() {
  213. return this.list.length && (this.isBatchRemove || this.listTopBtn.length)
  214. },
  215. isBatchRemove() {
  216. return this.columnData.btnsList.find(item => item.value === "batchRemove" && item.show)
  217. },
  218. showTabs() {
  219. return this.columnData?.tabConfig?.on && this.tabList.length
  220. },
  221. /* 底部自定义按钮 */
  222. bottomCustomBtnsList() {
  223. if (this.listTopBtn.length <= 3) return [this.listTopBtn, []];
  224. const firstArray = this.listTopBtn.slice(0, 3);
  225. const secondArray = this.listTopBtn.slice(3);
  226. return [firstArray, secondArray];
  227. },
  228. getRowKey() {
  229. return this.config.webType == 4 && this.columnData.viewKey ? this.columnData.viewKey : 'id'
  230. },
  231. isMoreBtn() {
  232. return this.columnData?.customBtnsList?.some(item => item.event?.btnType === 2);
  233. }
  234. },
  235. methods: {
  236. selectCheckbox(data) {
  237. this.selectItems = data
  238. },
  239. init() {
  240. this.userInfo = uni.getStorageSync('userInfo') || {};
  241. this.properties = this.config.flowTemplateJson ? JSON.parse(this.config.flowTemplateJson).properties : {};
  242. let columnDataStr = this.config?.appColumnData || '[]';
  243. try {
  244. this.columnData = JSON.parse(columnDataStr);
  245. } catch (e) {
  246. this.columnData = [];
  247. }
  248. this.permission = this.$permission.getPermission(this.columnData, this.menuId, this.jnpf.getScriptFunc);
  249. this.enableFunc = this.permission.enableFunc;
  250. this.upOption.page.size = this.columnData.hasPage ? this.columnData.pageSize : 1000000;
  251. this.setDefaultQuery();
  252. this.columnList = this.permission.columnPermission || [];
  253. this.columnData.customBtnsList = this.permission.customBtnsPermission || [];
  254. this.columnData.customBtnsList.map((o) => {
  255. if (o.labelI18nCode) o.label = this.$t(o.labelI18nCode)
  256. })
  257. this.setBtns()
  258. this.columnList = this.transformColumnList(this.columnList)
  259. this.columnList.map((o) => {
  260. if (o.labelI18nCode) o.label = this.$t(o.labelI18nCode)
  261. // if (o.jnpfKey != 'table' && o.label.length > 4) o.label = o.label.substring(0, 4)
  262. })
  263. this.sortList = this.columnList.filter(o => o.sortable)
  264. this.handleSearchList()
  265. this.handleSortList()
  266. this.handleDeleteBtn()
  267. this.key = +new Date()
  268. },
  269. setBtns() {
  270. const buttonsByPosition = this.columnData.customBtnsList.reduce((accumulator, item) => {
  271. if (item.event.position === 2) {
  272. accumulator.top.push(item);
  273. } else {
  274. accumulator.inner.push(item);
  275. }
  276. return accumulator;
  277. }, {
  278. inner: [],
  279. top: []
  280. });
  281. this.listInnerBtn = buttonsByPosition.inner;
  282. this.listTopBtn = buttonsByPosition.top;
  283. },
  284. upCallback(page) {
  285. if (this.isPreview == '1') return this.mescroll.endSuccess(0, false);
  286. const query = {
  287. currentPage: page.num,
  288. pageSize: page.size,
  289. menuId: this.menuId,
  290. modelId: this.modelId,
  291. ...this.listQuery
  292. }
  293. getModelList(this.modelId, query, {
  294. load: page.num == 1
  295. }).then(res => {
  296. this.selectItems = []
  297. this.$nextTick(() => {
  298. this.$refs.list.handleCheckAll()
  299. })
  300. this.showParser = true
  301. if (page.num == 1) this.list = [];
  302. this.mescroll.endSuccess(res.data.list.length);
  303. const list = res.data.list.map((o, i) => ({
  304. checked: false,
  305. index: i,
  306. ...o
  307. }));
  308. this.list = this.list.concat(list);
  309. this.$nextTick(() => {
  310. if (this.columnData.funcs && this.columnData.funcs.afterOnload) this
  311. .setTableLoadFunc()
  312. })
  313. if (!this.selectItems.length || !this.list.length) this.cancel()
  314. }).catch((err) => {
  315. this.mescroll.endByPage(0, 0);
  316. this.mescroll.endErr();
  317. })
  318. },
  319. //获取标签面板数据、设置标签面板默认值
  320. async getTabList() {
  321. this.tabList = [];
  322. if (!this.columnData.tabConfig) return;
  323. const list = this.columnData.columnOptions.filter(o => o.__vModel__ == this.columnData.tabConfig
  324. .relationField) || [];
  325. if (list?.length) {
  326. this.columnData.tabConfig?.hasAllTab && this.tabList.push({
  327. fullName: '全部',
  328. id: undefined
  329. });
  330. if (list[0].__config__.dataType == 'dictionary' && list[0].__config__.dictionaryType) {
  331. const data = await baseStore.getDicDataSelector(list[0].__config__.dictionaryType) || [];
  332. const options = list[0].props.value == 'enCode' ? data.map(o => ({
  333. ...o,
  334. id: o.enCode
  335. })) : data;
  336. this.tabList = [...this.tabList, ...options];
  337. } else {
  338. this.tabList = [...this.tabList, ...list[0].options];
  339. }
  340. }
  341. this.tabActiveKey = 0;
  342. this.onTabChange(this.tabActiveKey)
  343. },
  344. onTabChange(val) {
  345. this.tabActiveKey = val
  346. this.tabQueryJson = {}
  347. if (this.columnData.tabConfig.hasAllTab) {
  348. if (val != 0) {
  349. this.tabQueryJson = {
  350. [this.columnData.tabConfig.relationField]: this.tabList[val].id
  351. };
  352. }
  353. } else {
  354. this.tabQueryJson = {
  355. [this.columnData.tabConfig.relationField]: this.tabList[val].id
  356. };
  357. }
  358. let search = this.$refs.searchForm && this.$refs.searchForm.allCondition()
  359. this.listQuery.queryJson = JSON.stringify({
  360. ...search,
  361. ...this.tabQueryJson
  362. })
  363. this.initData();
  364. },
  365. handleSearchForm(data) {
  366. let newData = {};
  367. for (let key in data) {
  368. if (data.hasOwnProperty(key)) {
  369. if (typeof data[key] === 'object' && data[key] !== null) {
  370. for (let innerKey in data[key]) {
  371. if (data[key].hasOwnProperty(innerKey)) {
  372. let newKey = `${key}-${innerKey}`;
  373. newData[newKey] = data[key][innerKey];
  374. }
  375. }
  376. } else {
  377. newData[key] = data[key];
  378. }
  379. }
  380. }
  381. return newData
  382. },
  383. sumbitSearchForm(data) {
  384. let queryJson = data || {}
  385. this.searchFormData = data
  386. // 标签面板查询
  387. if (this.columnData.tabConfig && this.columnData.tabConfig.on) {
  388. this.tabQueryJson = {
  389. [this.columnData.tabConfig.relationField]: this.tabList[this.tabActiveKey]?.id
  390. };
  391. queryJson = {
  392. ...queryJson,
  393. ...this.tabQueryJson
  394. }
  395. }
  396. this.listQuery.queryJson = JSON.stringify(queryJson) !== '{}' ? JSON.stringify(queryJson) : ''
  397. this.$refs.uDropdown.close();
  398. this.$nextTick(() => {
  399. this.list = [];
  400. this.mescroll.resetUpScroll();
  401. })
  402. },
  403. // 处理启用规则
  404. customEnableRule(data, funcName) {
  405. // #ifdef MP-WEIXIN
  406. return true
  407. // #endif
  408. // #ifndef MP-WEIXIN
  409. let func = this.enableFunc[funcName]
  410. if (!func) return false
  411. let res = func.call(this, {
  412. row: data,
  413. rowIndex: data.index,
  414. onlineUtils: this.jnpf.onlineUtils,
  415. })
  416. return res
  417. // #endif
  418. },
  419. handleDeleteBtn() {
  420. if (this.config.webType == 4) return
  421. const actionOptions = this.columnData.columnBtnsList.filter(o => o.value == 'remove' && o.show)
  422. this.actionOptions = actionOptions.map(o => ({
  423. ...o,
  424. //#ifdef MP-WEIXIN
  425. text: o.labelI18nCode ? this.$t(o.labelI18nCode) : o.label,
  426. //#endif
  427. //#ifndef MP-WEIXIN
  428. text: o.labelI18nCode ? this.$t(o.labelI18nCode, o.label) : o.label,
  429. //#endif
  430. style: {
  431. backgroundColor: '#dd524d'
  432. }
  433. }))
  434. },
  435. handleSearchList() {
  436. this.searchList = (this.$u.deepClone(this.columnData.searchList) || []).filter(o => !o.noShow)
  437. for (let i = 0; i < this.searchList.length; i++) {
  438. const item = this.searchList[i]
  439. if (item.labelI18nCode) {
  440. item.label = this.$t(item.labelI18nCode)
  441. item.placeholder = this.$t(item.labelI18nCode)
  442. }
  443. const config = item.__config__
  444. if (item.value != null && item.value != '' && item.value != []) {
  445. this.searchFormData[item.id] = item.value;
  446. }
  447. if (this.config.webType == 4) config.label = item.label
  448. }
  449. if (Object.keys(this.searchFormData).length) this.listQuery.queryJson = JSON.stringify(this.searchFormData)
  450. if (this.searchList.some(o => o.isKeyword)) {
  451. const keywordItem = {
  452. id: 'jnpfKeyword',
  453. fullName: '关键词',
  454. prop: 'jnpfKeyword',
  455. label: this.$t('common.keyword'),
  456. jnpfKey: 'input',
  457. clearable: true,
  458. placeholder: '请输入',
  459. value: undefined,
  460. __config__: {
  461. jnpfKey: 'input'
  462. },
  463. };
  464. this.searchList.unshift(keywordItem);
  465. }
  466. this.searchFormConf = this.$u.deepClone(this.searchList)
  467. },
  468. handleSortList() {
  469. this.sortOptions = [];
  470. const sortList = this.sortList
  471. for (let i = 0; i < sortList.length; i++) {
  472. let ascItem = {
  473. label: sortList[i].label + ' ' + this.$t('app.apply.ascendingOrder'),
  474. value: sortList[i].prop,
  475. sidx: sortList[i].prop,
  476. sort: 'asc'
  477. }
  478. let descItem = {
  479. label: sortList[i].label + ' ' + this.$t('app.apply.descendingOrder'),
  480. value: '-' + sortList[i].prop,
  481. sidx: sortList[i].prop,
  482. sort: 'desc'
  483. }
  484. this.sortOptions.push(ascItem, descItem)
  485. }
  486. },
  487. transformColumnList(columnList) {
  488. let list = []
  489. for (let i = 0; i < columnList.length; i++) {
  490. const e = columnList[i];
  491. if (!e.prop.includes('-')) {
  492. e.option = null
  493. list.push(e)
  494. } else {
  495. let prop = e.prop.split('-')[0]
  496. let vModel = e.prop.split('-')[1]
  497. let label = e.label.split('-')[0]
  498. let childLabel = e.label.replace(label + '-', '');
  499. if (e.fullNameI18nCode && Array.isArray(e.fullNameI18nCode) && e.fullNameI18nCode[0]) {
  500. label = this.$t(e.fullNameI18nCode[0], label);
  501. }
  502. let newItem = {
  503. align: "center",
  504. jnpfKey: "table",
  505. prop,
  506. label,
  507. children: []
  508. }
  509. e.vModel = vModel
  510. e.childLabel = e.labelI18nCode ? this.$t(e.labelI18nCode) : childLabel;
  511. if (!list.some(o => o.prop === prop)) list.push(newItem)
  512. for (let i = 0; i < list.length; i++) {
  513. if (list[i].prop === prop) {
  514. e.option = null
  515. list[i].children.push(e)
  516. break
  517. }
  518. }
  519. }
  520. }
  521. return list
  522. },
  523. setDefaultQuery() {
  524. const defaultSortConfig = (this.columnData.defaultSortConfig || []).map(o =>
  525. (o.sort === 'desc' ? '-' : '') + o.field);
  526. this.listQuery.sidx = defaultSortConfig.join(',')
  527. },
  528. setTableLoadFunc() {
  529. const JNPFTable = this.$refs.tableRef
  530. const parameter = {
  531. data: this.list,
  532. tableRef: JNPFTable,
  533. onlineUtils: this.jnpf.onlineUtils,
  534. }
  535. const func = this.jnpf.getScriptFunc.call(this, this.columnData.funcs.afterOnload)
  536. if (!func) return
  537. func.call(this, parameter)
  538. },
  539. //删除操作
  540. handleClick(index) {
  541. const item = this.list[index]
  542. if (!this.permission.btnPermission.includes('btn_remove')) return this.$u.toast("未开启删除权限")
  543. if (!this.customEnableRule(item, 'remove')) return this.$u.toast("没有删除权限")
  544. let txt = '流程处于暂停状态,不可操作'
  545. if ([1, 2, 3, 4, 6, 7, 8].includes(item.flowState)) txt = '流程已受理,无法删除'
  546. uni.showModal({
  547. title: '提示',
  548. content: '删除后数据无法恢复',
  549. success: (res) => {
  550. if (res.confirm) {
  551. if (this.config.enableFlow == 1 && ![0, 9].includes(item.flowState)) {
  552. this.$u.toast(txt)
  553. return
  554. }
  555. let data = {
  556. flowId: this.config.flowId,
  557. ids: [item.id]
  558. }
  559. deteleModel(data, this.modelId).then(res => {
  560. this.$u.toast(res.msg)
  561. this.list.splice(index, 1)
  562. this.mescroll.resetUpScroll()
  563. })
  564. }
  565. }
  566. })
  567. },
  568. //底部更多按钮
  569. handleBottomMoreClick(type) {
  570. this.showBottomMoreBtn = true
  571. },
  572. //更多按钮弹窗
  573. handleMoreClick(index) {
  574. this.selectListIndex = index
  575. this.showMoreBtn = true
  576. },
  577. //底部按钮操作
  578. bottomBtnConfirm(e) {
  579. if (Array.isArray(e) && e.length) {
  580. const index = this.bottomCustomBtnsList[1].findIndex(item => item.value === e[0].value);
  581. const item = this.bottomCustomBtnsList[1][index];
  582. if (item.event && item.event.btnType === 3) this.handleBottomBtnInterface(item.event);
  583. if (item.event.btnType == 2) this.handleScriptFunc(item.event, this.selectItems)
  584. if (item.event.btnType == 4) this.handleLaunchFlow(item, this.selectItems)
  585. } else {
  586. // 当e是一个对象且包含event属性时
  587. if (e.event.btnType == 2) this.handleScriptFunc(e.event, this.selectItems)
  588. if (e.event.btnType === 3) this.handleBottomBtnInterface(e.event);
  589. if (e.event.btnType == 4) this.handleLaunchFlow(e, this.selectItems)
  590. }
  591. },
  592. //底部自定义按钮接口操作
  593. handleBottomBtnInterface(item) {
  594. const selectedItemsCopy = [...this.selectItems];
  595. const webType = this.config.webType;
  596. let data = {
  597. items: selectedItemsCopy,
  598. webType
  599. };
  600. const handlerInterface = (data) => {
  601. let query = {
  602. paramList: this.jnpf.getBatchParamList(item.templateJson, data) || [],
  603. }
  604. getDataInterfaceRes(item.interfaceId, query).then(res => {
  605. uni.showToast({
  606. title: res.msg,
  607. icon: 'none'
  608. })
  609. })
  610. }
  611. if (!item.useConfirm) return handlerInterface(data)
  612. uni.showModal({
  613. title: this.$t('common.tipTitle'),
  614. content: item.confirmTitle || '确认执行此操作?',
  615. showCancel: true,
  616. confirmText: '确定',
  617. success: function(res) {
  618. if (res.confirm) {
  619. handlerInterface(data)
  620. }
  621. }
  622. });
  623. },
  624. // 自定义按钮事件
  625. selectBtnconfirm(e) {
  626. var i = this.columnData.customBtnsList.findIndex((item) => {
  627. return item.value == e[0].value
  628. })
  629. const item = this.columnData.customBtnsList[i]
  630. const row = this.list[this.selectListIndex]
  631. const index = this.selectListIndex
  632. // 自定义启用规则判断
  633. if (!this.customEnableRule(row, item.value)) return this.$u.toast('没有' + item.label + '权限')
  634. if (item.event.btnType == 1) this.handlePopup(item.event, row)
  635. if (item.event.btnType == 2) this.handleScriptFunc(item.event, row, index)
  636. if (item.event.btnType == 3) this.handleInterface(item.event, row)
  637. if (item.event.btnType == 4) this.handleLaunchFlow(item, [row])
  638. },
  639. //自定义按钮发起流程
  640. handleLaunchFlow(item, records) {
  641. const data = deepClone(item.event.launchFlow)
  642. let dataList = [];
  643. for (let i = 0; i < records.length; i++) {
  644. dataList.push(this.jnpf.getLaunchFlowParamList(data.transferList, records[i], this.getRowKey));
  645. }
  646. const query = {
  647. template: data.flowId,
  648. btnCode: item.value,
  649. currentUser: data.currentUser,
  650. customUser: data.customUser,
  651. initiator: data.initiator,
  652. dataList,
  653. };
  654. launchFlow(query, this.modelId).then(res => {});
  655. },
  656. //自定义按钮弹窗操作
  657. handlePopup(item, row) {
  658. this.handleListen()
  659. let data = {
  660. config: item,
  661. modelId: this.modelId,
  662. id: this.config.webType == 4 ? '' : row[this.getRowKey],
  663. isPreview: this.isPreview,
  664. row: this.config.webType == 4 ? row : '',
  665. }
  666. data = encodeURIComponent(JSON.stringify(data))
  667. uni.navigateTo({
  668. url: '/pages/apply/customBtn/index?data=' + data
  669. })
  670. },
  671. //自定义按钮JS操作
  672. handleScriptFunc(item, row, index) {
  673. const parameter = {
  674. data: row,
  675. index,
  676. refresh: this.initData,
  677. onlineUtils: this.jnpf.onlineUtils,
  678. }
  679. const func = this.jnpf.getScriptFunc.call(this, item.func)
  680. if (!func) return
  681. func.call(this, parameter)
  682. },
  683. //自定义按钮接口操作
  684. handleInterface(item, row) {
  685. const handlerData = () => {
  686. getModelInfo(this.modelId, row[this.getModelInfo]).then(res => {
  687. const dataForm = res.data || {};
  688. if (!dataForm.data) return;
  689. const data = {
  690. ...JSON.parse(dataForm.data),
  691. id: row[this.getModelInfo]
  692. };
  693. handlerInterface(data);
  694. })
  695. }
  696. const handlerInterface = (data) => {
  697. let query = {
  698. paramList: this.jnpf.getParamList(item.templateJson, {
  699. ...data,
  700. id: row[this.getRowKey]
  701. }, this.getRowKey) || [],
  702. }
  703. getDataInterfaceRes(item.interfaceId, query).then(res => {
  704. uni.showToast({
  705. title: res.msg,
  706. icon: 'none'
  707. })
  708. if (item.isRefresh) this.initData();
  709. })
  710. }
  711. const handleFun = () => {
  712. this.config.webType == '4' ? handlerInterface(row) : handlerData();
  713. };
  714. if (!item.useConfirm) return handleFun()
  715. uni.showModal({
  716. title: '提示',
  717. content: item.confirmTitle || '确认执行此操作',
  718. success: (res) => {
  719. if (!res.cancel) handleFun()
  720. }
  721. })
  722. },
  723. initData() {
  724. this.list = [];
  725. this.$nextTick(() => {
  726. this.mescroll.resetUpScroll();
  727. })
  728. },
  729. search() {
  730. if (this.isPreview == '1') return
  731. this.searchTimer && clearTimeout(this.searchTimer)
  732. this.searchTimer = setTimeout(() => {
  733. this.list = [];
  734. this.mescroll.resetUpScroll();
  735. }, 300)
  736. },
  737. handleListen() {
  738. uni.$off('refresh')
  739. uni.$on('refresh', () => {
  740. this.list = [];
  741. this.mescroll.resetUpScroll();
  742. })
  743. },
  744. addPage() {
  745. this.handleListen()
  746. this.jumPage({}, '')
  747. },
  748. jumPage(item, btnType) {
  749. if (!item.id && !item.flowState) btnType = 'btn_add'
  750. if (this.config.enableFlow == 1) {
  751. if (item.id) {
  752. if (!this.permission.btnPermission.includes('btn_edit') && item.flowState == 3) return
  753. if (!this.permission.btnPermission.includes('btn_detail') && ![0, 8, 9].includes(item
  754. .flowState))
  755. return
  756. }
  757. let opType = '-1'
  758. if (![0, 8, 9].includes(item.flowState) && btnType != 'btn_add') opType = 0
  759. const config = {
  760. id: item.flowTaskId || item.id || '',
  761. flowId: this.config.flowId,
  762. opType,
  763. status: item.flowState || '',
  764. isPreview: this.isPreview,
  765. taskId: item.flowTaskId || item.id,
  766. isFlow: 0,
  767. }
  768. uni.navigateTo({
  769. url: '/pages/workFlow/flowBefore/index?config=' +
  770. this.jnpf.base64.encode(JSON.stringify(config))
  771. })
  772. } else {
  773. const type = btnType == 'btn_detail' ? 'detail' : 'form'
  774. const currentMenu = encodeURIComponent(JSON.stringify(this.permission.formPermission))
  775. let btnType_ = this.permission.btnPermission.includes('btn_edit') ? 'btn_edit' : 'btn_add'
  776. let enableEdit = this.customEnableRule(item, 'edit')
  777. let labelS = {}
  778. for (let i = 0; i < this.columnData.columnBtnsList.length; i++) {
  779. const item = this.columnData.columnBtnsList[i]
  780. if (item.value == 'edit') {
  781. labelS[btnType_] = item.labelI18nCode ? this.$t(item.labelI18nCode) : item.label
  782. }
  783. }
  784. const config = {
  785. currentMenu,
  786. btnType: btnType_,
  787. list: this.list,
  788. modelId: this.modelId,
  789. isPreview: this.isPreview,
  790. id: item.id || '',
  791. index: item.index,
  792. enableEdit,
  793. labelS
  794. }
  795. const url = '/pages/apply/dynamicModel/' + type + '?config=' +
  796. this.jnpf.base64.encode(JSON.stringify(config))
  797. uni.navigateTo({
  798. url: url
  799. })
  800. }
  801. },
  802. goDetail(item) {
  803. if (this.config.webType == 4) return
  804. this.handleListen()
  805. let hasDetail = this.permission.btnPermission.includes('btn_detail')
  806. let hasEdit = this.permission.btnPermission.includes('btn_edit')
  807. if (!hasDetail && !hasEdit) return
  808. if (hasDetail) {
  809. if (this.customEnableRule(item, 'detail')) {
  810. return this.jumPage(item, 'btn_detail')
  811. }
  812. if (this.customEnableRule(item, 'edit')) {
  813. return this.jumPage(item, 'btn_edit')
  814. }
  815. } else {
  816. if (this.customEnableRule(item, 'edit')) {
  817. return this.jumPage(item, 'btn_edit')
  818. }
  819. }
  820. },
  821. cellClick(item) {
  822. if (this.isPreview == '1') return this.$u.toast('功能预览不支持排序')
  823. const findIndex = this.sortValue.findIndex(o => o === item.value);
  824. if (findIndex < 0) {
  825. const findLikeIndex = this.sortValue.findIndex(o => o.indexOf(item.sidx) > -1);
  826. if (findLikeIndex > -1) this.sortValue.splice(findLikeIndex, 1)
  827. this.sortValue.push(item.value)
  828. } else {
  829. this.sortValue.splice(findIndex, 1)
  830. }
  831. },
  832. handleReset() {
  833. this.searchFormData = {}
  834. const list = ['datePicker', 'timePicker', 'inputNumber', 'calculate', 'cascader', 'organizeSelect']
  835. for (let i = 0; i < this.searchList.length; i++) {
  836. const item = this.searchList[i]
  837. const config = item.__config__
  838. let defaultValue = item.searchMultiple || list.includes(config.jnpfKey) ? [] : undefined
  839. if (config.isFromParam) defaultValue = undefined
  840. config.defaultValue = defaultValue
  841. this.searchFormData[item.id] = item.value || defaultValue
  842. }
  843. this.searchFormConf = JSON.parse(JSON.stringify(this.searchList))
  844. },
  845. handleSearch() {
  846. if (this.isPreview == '1') return this.$u.toast('功能预览不支持检索')
  847. this.$refs.searchForm && this.$refs.searchForm.submitForm()
  848. },
  849. relationFormClick(item, column) {
  850. let vModel = column.vModel ? column.vModel : column.__vModel__
  851. let model_id = column.modelId
  852. let config = {
  853. modelId: model_id,
  854. isPreview: true,
  855. id: item[vModel + '_id'],
  856. sourceRelationForm: true,
  857. noShowBtn: 1,
  858. noDataLog: 1,
  859. propsValue: column.propsValue
  860. }
  861. const url =
  862. '/pages/apply/dynamicModel/detail?config=' + this.jnpf.base64.encode(JSON.stringify(config))
  863. uni.navigateTo({
  864. url: url
  865. })
  866. },
  867. handleSortReset() {
  868. this.sortValue = []
  869. },
  870. handleSortSearch() {
  871. if (this.sortValue.length) {
  872. this.listQuery.sidx = this.sortValue.join(',')
  873. } else {
  874. this.setDefaultQuery()
  875. }
  876. this.$refs.uDropdown.close();
  877. this.$nextTick(() => {
  878. this.list = [];
  879. this.mescroll.resetUpScroll();
  880. })
  881. }
  882. }
  883. }
  884. </script>
  885. <style lang="scss">
  886. page {
  887. background-color: #f0f2f6;
  888. height: 100%;
  889. /* #ifdef MP-ALIPAY */
  890. position: absolute;
  891. top: 0;
  892. left: 0;
  893. width: 100%;
  894. /* #endif */
  895. }
  896. .top-btn {
  897. height: 80rpx;
  898. position: fixed;
  899. width: 100%;
  900. top: 0;
  901. left: 0;
  902. background-color: #fff;
  903. /* #ifdef MP-WEIXIN */
  904. z-index: 99;
  905. /* #endif */
  906. /* #ifndef MP-WEIXIN */
  907. z-index: 999;
  908. /* #endif */
  909. justify-content: space-between;
  910. padding: 0 20rpx;
  911. .button-left {
  912. color: #0293fc;
  913. }
  914. .button-right {
  915. width: 30rpx;
  916. height: 30rpx;
  917. }
  918. }
  919. .slide-down2 {
  920. animation: slide-down2 0.5s forwards;
  921. opacity: 1;
  922. transform: translateY(0);
  923. }
  924. .slide-up2 {
  925. animation: slide-up2 0.5s forwards;
  926. opacity: 0;
  927. transform: translateY(-100%);
  928. }
  929. .slide-down {
  930. animation: slide-down 0.5s forwards;
  931. opacity: 1;
  932. transform: translateY(0);
  933. }
  934. .slide-up {
  935. animation: slide-up 0.5s forwards;
  936. opacity: 0;
  937. transform: translateY(100%);
  938. }
  939. .bottom-btn {
  940. height: 100rpx;
  941. position: fixed;
  942. width: 100%;
  943. bottom: 0;
  944. left: 0;
  945. background-color: #0293fc;
  946. z-index: 9;
  947. justify-content: space-around;
  948. .button-preIcon {
  949. color: #fff;
  950. text-align: center;
  951. width: 20%;
  952. .btn-icon {
  953. height: 32rpx;
  954. }
  955. }
  956. }
  957. @keyframes slide-up {
  958. to {
  959. transform: translateY(0);
  960. opacity: 1;
  961. }
  962. }
  963. @keyframes slide-down {
  964. to {
  965. transform: translateY(100%);
  966. opacity: 0;
  967. }
  968. }
  969. @keyframes slide-up2 {
  970. to {
  971. transform: translateY(0);
  972. opacity: 1;
  973. }
  974. }
  975. @keyframes slide-down2 {
  976. to {
  977. transform: translateY(-100%);
  978. opacity: 0;
  979. }
  980. }
  981. :deep(.u-cell) {
  982. padding: 0rpx;
  983. height: 112rpx;
  984. }
  985. .buttom-actions {
  986. z-index: 1;
  987. }
  988. .screen-box {
  989. background-color: #fff;
  990. height: 100%;
  991. .screen-btn {
  992. width: 100%;
  993. height: 2.75rem;
  994. .btn {
  995. width: 50%;
  996. height: 2.75rem;
  997. text-align: center;
  998. line-height: 2.75rem;
  999. box-shadow: 0px -4rpx 20rpx #F8F8F8
  1000. }
  1001. .btn1 {
  1002. color: #606266;
  1003. }
  1004. .btn2 {
  1005. background-color: #2979ff;
  1006. color: #fff;
  1007. }
  1008. }
  1009. .screen-list {
  1010. width: 100%;
  1011. height: 100%;
  1012. .list {
  1013. height: calc(100% - 88rpx);
  1014. overflow-y: scroll;
  1015. }
  1016. }
  1017. }
  1018. .notData-box {
  1019. width: 100%;
  1020. height: 100%;
  1021. justify-content: center;
  1022. align-items: center;
  1023. padding-bottom: 200rpx;
  1024. .notData-inner {
  1025. width: 280rpx;
  1026. height: 308rpx;
  1027. align-items: center;
  1028. .iconImg {
  1029. width: 100%;
  1030. height: 100%;
  1031. }
  1032. .notData-inner-text {
  1033. padding: 30rpx 0;
  1034. color: #909399;
  1035. }
  1036. }
  1037. }
  1038. </style>