123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- <template>
- <Page :title='`${queryParameters.name}列表`'>
- <template v-slot:body>
- <div class="flex flex-col h-full">
- <!-- 搜索 -->
- <div class="mx-1 headerModeuleList">
- <van-search v-model.trim="searchVal" background="#F8F8F8" :placeholder="`请输入${queryParameters?.name}关键词`"
- @search="onRefresh(true)" @clear="onRefresh(true)">
- <template v-slot:left-icon>
- <van-icon name="search" class="themeTextColor font-bold" />
- </template>
- </van-search>
- </div>
- <!-- 主题内容 -->
- <div class="flex-1 overflow-y-auto">
- <template v-if="listData?.records && listData.records.length && !loadingList">
- <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
- <van-list v-model:loading="isLoading" :finished="finished" finished-text="没有更多了" @load="onLoad">
- <div v-for="item in listData.records" :key="item.id" @click="toDetail(item)">
- <van-swipe-cell>
- <div
- :class="`${item.needPin ? 'bg-slate-50' : 'bg-white'} px-5 py-5 flex items-center flex-row w-full listContent`">
- <div class="listOfImages items-justify-center rounded-full overflow-hidden bg-[#FFEEEC]">
- <img :src="queryParameters.homeImage" class="w-full h-full">
- </div>
- <div class="flex-1 h-full">
- <!-- 商机 -->
- <template v-if="queryParameters?.key == 'business'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.name }}</div>
- <div><van-tag type="primary">{{ item.stageValue }}</van-tag></div>
- </div>
- <div class="flex items-center flex-row mt-1">
- <van-text-ellipsis :content="item.customerName"
- class="flex-1 text-[#B9B9B9] text-size-small" />
- <div class="text-[#B9B9B9] text-size-small" v-if="item.inchargerName">负责人:{{
- item.inchargerName }}</div>
- </div>
- </div>
- </template>
- <!-- 线索 -->
- <template v-if="queryParameters?.key == 'thread'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.clueName }}</div>
- <div class="text-[#B9B9B9]">{{ item.customerLevelValue }}</div>
- </div>
- <div class="flex items-center flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small" v-if="item.inchargerName">负责人:{{
- item.inchargerName }}</div>
- <div></div>
- </div>
- </div>
- </template>
- <!-- 客户 -->
- <template v-if="queryParameters?.key == 'customer'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.customName }}</div>
- <div class="text-[#B9B9B9]">{{ item.customerLevelValue }}</div>
- </div>
- <div class="flex items-center flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small" v-if="item.inchargerName">负责人:{{
- item.inchargerName }}</div>
- <div></div>
- </div>
- </div>
- </template>
- <!-- 联系人 -->
- <template v-if="queryParameters?.key == 'contacts'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.name }}</div>
- <div class="text-[#B9B9B9]">{{ item.position }}</div>
- </div>
- <div class="flex items-center justify-between flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small w-2/5 truncate" v-if="item.ownerName">客户:{{
- item.customName }}</div>
- <div class="text-[#B9B9B9] text-size-small w-2/5 truncate text-right" v-if="item.ownerName">负责人:{{
- item.ownerName }}</div>
- </div>
- </div>
- </template>
- <!-- 任务 -->
- <template v-if="queryParameters?.key == 'tasks'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.taskName }}</div>
- <div :style="`color: ${fixedFieldTaskStatus.find(subItem => subItem.value == item.status)?.color}`">
- {{ fixedFieldTaskStatus.find(subItem => subItem.value == item.status)?.label || '' }}
- </div>
- </div>
- <div class="flex items-center justify-between flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small w-2/5 truncate">
- {{ item.businessName || item.orderName || item.clueName || item.customName }}
- </div>
- <div class="text-[#B9B9B9] text-size-small w-2/5 truncate text-right">优先级:
- {{ fixedFieldPriority.find(subItem => subItem.value == item.priority)?.label || '' }}
- </div>
- </div>
- </div>
- </template>
- <!-- 产品 -->
- <template v-if="queryParameters?.key == 'product'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.productName }}</div>
- <div class="text-[#B9B9B9]">{{ item.status ? '上架' : '下架' }}</div>
- </div>
- <div class="flex items-center justify-between flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small w-2/5 truncate">负责人:{{
- item.inchargerName }}</div>
- <div class="text-[#B9B9B9] text-size-small w-2/5 truncate text-right">库存:{{
- item.unit || 0 }}</div>
- </div>
- </div>
- </template>
- <!-- 合同 -->
- <template v-if="queryParameters?.key == 'contract'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.name }}</div>
- <div class="text-[#B9B9B9]">
- <span :style="fixedFieldStatusArray[item.status].color">
- {{ fixedFieldStatusArray[item.status].label }}
- </span>
- </div>
- </div>
- <div class="flex items-center justify-between flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small w-2/6 truncate">{{ item.number }}</div>
- <div class="text-[#B9B9B9] text-size-small w-2/3 truncate text-right">
- 合同金额¥{{ item.amounts }} / 回款进度 {{ item.payment ? (100 * item.payment / item.amounts).toFixed(1) + '%' : '0%' }}
- </div>
- </div>
- </div>
- </template>
- <!-- 销售 -->
- <template v-if="queryParameters?.key == 'order'">
- <div>
- <div class="flex items-center flex-row">
- <div class="flex-1 truncate mr-8 titles relative">{{ item.orderName }}</div>
- <div class="text-[#B9B9B9]">{{ fixedFieldPaymentStatus.find(subItem => subItem.value == item.receivedStatus)?.label || '' }}</div>
- </div>
- <div class="flex items-center justify-between flex-row mt-1">
- <div class="text-[#B9B9B9] text-size-small w-2/6 truncate">{{ item.customName }}</div>
- <div class="text-[#B9B9B9] text-size-small w-2/3 truncate text-right">
- 订单金额¥{{ item.price }} / 已回款¥ {{ item.receivedPayment }}
- </div>
- </div>
- </div>
- </template>
- </div>
- </div>
- <template #right>
- <div class="flex items-center h-full bg-white">
- <template v-if="!item.inchargerName">
- <div class="buttonCircle rounded-full" @click="claimAndClaim(item)" v-if="['business', 'thread',
- 'customer', 'product'].includes(queryParameters?.key)">
- <img src="/src/assets/image/claimAndClaim.png" class="w-full h-full">
- </div>
- </template>
- <template v-if="item.inchargerName || item.ownerName">
- <div class="buttonCircle rounded-full" @click="transfer(item)" v-if="['business', 'thread',
- 'customer', 'contacts', 'product', 'order'].includes(queryParameters?.key)">
- <img src="/src/assets/image/transfer.png" class="w-full h-full">
- </div>
- </template>
- <template v-if="!item.needPin">
- <div class="buttonCircle rounded-full" @click="topMounted(item)">
- <img src="/src/assets/image/topMounted.png" class="w-full h-full">
- </div>
- </template>
- <template v-if="item.needPin">
- <div class="buttonCircle rounded-full" @click="noTopMounted(item)">
- <img src="/src/assets/image/noTopMounted.png" class="w-full h-full">
- </div>
- </template>
- <div class="buttonCircle rounded-full" @click="edit(item)" v-permission="[queryParameters?.jurisdiction?.edit]">
- <img src="/src/assets/image/edit.png" class="w-full h-full">
- </div>
- <div class="buttonCircle rounded-full" @click="deleteRow(item)" v-permission="[queryParameters?.jurisdiction?.delete]">
- <img src="/src/assets/image/delete.png" class="w-full h-full">
- </div>
- </div>
- </template>
- </van-swipe-cell>
- </div>
- </van-list>
- </van-pull-refresh>
- </template>
- <template v-else>
- <template v-if="!isLoading && listData?.records && !listData.records.length">
- <van-empty description="暂无数据" />
- </template>
- <template v-else>
- <van-skeleton title :row="20" class="w-full h-full" />
- </template>
- </template>
- </div>
- </div>
- <!-- 可拖拽添加 -->
- <DragBox>
- <div class="addButton" @click="toAddEditor()" v-permission="[queryParameters?.jurisdiction?.newlyAdded]">
- <img src="/src/assets/image/add.png" class="w-full h-full" />
- </div>
- </DragBox>
- <!-- 转移弹窗 -->
- <van-dialog v-model:show="showDialog" :title="`转移${queryParameters?.name || ''}`" show-cancel-button
- @confirm="confirmTransfer" :before-close="dialogCloseBefo">
- <van-cell title="转移至" is-link @click="showSelect = true">
- <template #value>
- {{ dialogSelection.label }}
- </template>
- </van-cell>
- <div class="themeTextColor text-size-small pl-4 pt-2 pb-2">转移后,将看不到此{{ queryParameters?.name || '' }}</div>
- </van-dialog>
- <!-- select 选择器 -->
- <van-popup v-model:show="showSelect" destroy-on-close position="bottom" :style="{ height: '80%' }">
- <PullDownSelector :showElement="showSelect" @change="selectChange" />
- </van-popup>
- </template>
- </Page>
- </template>
- <script setup>
- import { ref, onActivated } from 'vue';
- import { showConfirmDialog } from 'vant';
- import { useLifecycle } from '@hooks/useCommon.js';
- import { resetListData, getListFieldKey } from '@components/common/formForm/formCorrespondenceProcessing'
- import useShowToast from '@hooks/useToast'
- import { GET_CUSTOM_FORM_JSON } from '@hooks/useApi'
- import { fixedFieldPaymentStatus, fixedFieldPriority, fixedFieldTaskStatus, fixedFieldStatusArray } from "@utility/defaultData"
- import requests from "@common/requests";
- import useRouterStore from "@store/useRouterStore.js";
- import useFixedData from "@store/useFixedData.js"
- import useInfoStore from '@store/useInfoStore'
- // import ElementLongPress from "@components/common/elementLongPress.vue";
- import DragBox from '@components/common/dragBox.vue';
- const TRANSFER = 'transfer';
- const DELETE = 'delete';
- const EDIT = 'edit';
- const TOP_MOUNTED = 'topMounted';
- const { toastSuccess, toastFail, toastText } = useShowToast()
- const router = useRouterStore()
- const fixedData = useFixedData()
- const userInfo = useInfoStore()
- const searchVal = ref()
- const queryParameters = ref({})
- const loadingList = ref(false)
- const popUpWindowArray = ref([
- { text: '转移', event: TRANSFER, icon: '/src/assets/image/transfer.png', removeModule: ['contacts', 'tasks', 'product', 'contract', 'order'] },
- { text: '顶置', event: TOP_MOUNTED, icon: '/src/assets/image/topMounted.png', removeModule: [] },
- { text: '编辑', event: EDIT, icon: '/src/assets/image/edit.png', removeModule: [] },
- { text: '删除', event: DELETE, icon: '/src/assets/image/delete.png', removeModule: [] },
- ])
- const showSelect = ref(false)
- const showDialog = ref(false)
- const refreshing = ref(false);
- const isLoading = ref(false);
- const finished = ref(false);
- const listData = ref({
- records: [],
- pageIndex: 0,
- pageSize: 20,
- total: 0,
- totalPage: 0,
- });
- const excessiveData = ref({});
- const dialogSelection = ref({});
- const timeout = ref(null)
- // 按钮触发的事件: row 为当前点击的行数据, item 为当前点击的按钮
- function longPress(row, item) {
- switch (item.event) {
- case EDIT:
- edit(row);
- break;
- case TRANSFER:
- transfer(row);
- break;
- case DELETE:
- deleteRow(row);
- break;
- case TOP_MOUNTED:
- topMounted(row);
- break;
- default:
- console.warn('未知的类型', item.event);
- break;
- }
- }
- // 编辑事件
- function edit(row) {
- const formJson = fixedData.formJson[queryParameters.value.key] || []
- const formList = resetListData(formJson?.list)
- const filedObj = getListFieldKey(formList, row)
- let other = {}
- if (queryParameters.value.key == 'tasks') {
- other = { ...row }
- }
- toAddEditor({ ...other, ...filedObj, id: row.id })
- }
- // 转移事件
- function transfer(row) {
- dialogSelection.value = {}
- excessiveData.value = row
- showDialog.value = true
- }
- function confirmTransfer() {
- if (!dialogSelection.value.label) {
- return toastText('请选择要转移的人员')
- }
- const { id } = excessiveData.value
- const { value } = dialogSelection.value
- let formVal = {}
- if(queryParameters?.value.key == 'contacts') {
- formVal = { id, inchargerId: value, ownerId: value }
- } else if(queryParameters?.value.key == 'product' || queryParameters?.value.key == 'order') {
- formVal = { id, userId: value }
- } else {
- formVal = { ids: id, inchargerId: value, }
- }
- requests.post(queryParameters?.value.transferInterface, { ...formVal }).then((res) => {
- toastSuccess('转移成功')
- onRefresh(true)
- showDialog.value = false
- })
- }
- // 认领
- function claimAndClaim(item) {
- const { id, name, clueName, customName, productName } = item
- const { key } = queryParameters.value
- const userId = userInfo.userInfo.id
- const formVal = {
- [key == 'product' ? 'id' : 'ids']: id,
- [key == 'product' ? 'userId' : 'inchargerId']: userId
- }
- showConfirmDialog({
- title: `认领${queryParameters.value.name}`,
- message: `确定认领【${name || clueName || customName || productName}】${queryParameters.value.name}吗?`,
- }).then(() => {
- requests.post(queryParameters?.value.transferInterface, { ...formVal }).then((res) => {
- toastSuccess('认领成功')
- onRefresh(true)
- })
- })
- }
- // 删除事件
- function deleteRow(row) {
- const { name = '', searchFiled = {}, deteleFiled = '' } = queryParameters.value
- const foemVal = { [queryParameters.value.key == 'tasks' ? 'taskIds' : queryParameters.value.key == 'contract' ? 'id' : 'ids']: row.id }
- showConfirmDialog({
- title: `删除${name}`,
- message: `确定删除【${row[searchFiled?.search]}】${name}吗?`,
- }).then(() => {
- requests.post(deteleFiled, { ...foemVal }).then((res) => {
- toastSuccess('删除成功')
- onRefresh(true)
- }).catch((err) => {
- toastFail(err.msg ? err.msg : '删除失败')
- })
- })
- }
- // 顶置事件
- function topMounted(row) {
- requests.post(queryParameters?.value.topMountedInterface, { id: row.id }).then((res) => {
- toastSuccess('顶置成功')
- onRefresh(true)
- })
- }
- function noTopMounted(row) {
- requests.post(queryParameters?.value.cancelTheTopMountedInterface, { id: row.id }).then((res) => {
- toastSuccess('取消顶置成功')
- onRefresh(true)
- })
- }
- function toDetail(item) {
- router.navigateTo({
- pathName: 'details',
- success: () => {
- router.emit('detailParameter', {
- routerInfo: JSON.stringify(queryParameters.value),
- parameter: JSON.stringify(item)
- })
- }
- })
- }
- function toAddEditor(value) {
- router.navigateTo({
- pathName: 'addEditor',
- success: () => {
- router.emit('addEditorParameter', {
- routerInfo: JSON.stringify(queryParameters.value),
- filedValue: JSON.stringify(value)
- })
- }
- })
- }
- function onRefresh(flag = false) {
- finished.value = false;
- isLoading.value = true;
- listData.value.pageIndex = 1;
- fetchListData(flag);
- }
- function onLoad() {
- isLoading.value = true;
- listData.value.pageIndex++
- fetchListData()
- }
- async function fetchListData(flag = false) {
- console.log(listData.value.totalPage, listData.value.pageIndex)
- if (
- // 如果总页数小于等于现页数,并且不是第一次加载, 或者正在加载数据 直接跳出不请求
- listData.value.totalPage < listData.value.pageIndex &&
- listData.value.pageIndex !== 1
- ) {
- finished.value = true;
- return;
- }
- const res = await getListData(flag)
- if (res.code === 'ok') {
- const list = res.data.data || res.data.records || res.data.record
- const total = res.data.total
- if (refreshing.value) {
- refreshing.value = false;
- }
- isLoading.value = false;
- listData.value.records = (
- listData.value.pageIndex === 1 ? [] : listData.value.records
- ).concat(list || [])
- listData.value.totalPage = Math.ceil(total / listData.value.pageSize)
- listData.value.total = +total
- }
- }
- async function getListData(flag = false) {
- const url = queryParameters.value.listUrl
- if (flag) {
- loadingList.value = true
- }
- let formVal = {
- pageIndex: listData.value.pageIndex,
- pageSize: listData.value.pageSize,
- pageFrom: listData.value.pageSize,
- [queryParameters.value?.searchFiled?.search]: searchVal.value,
- }
- const res = await requests.post(url, { ...formVal }).finally(() => {
- if (flag) {
- loadingList.value = false
- }
- })
- return res
- }
- function reloadListData(data) {
- queryParameters.value = JSON.parse(data.row || '{}')
- refreshing.value = false
- isLoading.value = false
- finished.value = false
- searchVal.value = ''
- listData.value = { records: [], pageIndex: 0, pageSize: 20, total: 0, totalPage: 0 }
- popUpWindowArray.value = popUpWindowArray.value.filter(item => !item.removeModule.includes(queryParameters.value?.key))
- if (!fixedData.formJson[queryParameters.value.key]) {
- getFormJson(queryParameters.value)
- }
- onLoad()
- }
- function getFormJson(info = {}) {
- requests.get(`${GET_CUSTOM_FORM_JSON}/${info.key}`).then(res => {
- const { data = [] } = res
- fixedData.updateState({
- formJson: {
- ...fixedData.formJson,
- [info.key]: JSON.parse(data[0].config)
- }
- })
- })
- }
- function selectChange(value, label) {
- dialogSelection.value = {
- value, label
- }
- showSelect.value = false
- }
- function dialogCloseBefo(val) {
- if (val == 'confirm' && showDialog.value) {
- return false
- }
- return true
- }
- function chuliReloadListData(data) {
- clearTimeout(timeout.value);
- timeout.value = setTimeout(() => {
- reloadListData(data)
- }, 100);
- }
- function chuliOnRefresh(data) {
- clearTimeout(timeout.value);
- timeout.value = setTimeout(() => {
- onRefresh(true)
- }, 100);
- }
- useLifecycle({
- load: () => {
- chuliOnRefresh(true)
- router.on('moduleListDetailParameter', (data) => {
- chuliReloadListData(data)
- })
- router.eventOn('moduleListRefreshData', (data) => {
- chuliOnRefresh(true)
- })
- }
- });
- </script>
- <style lang='scss' scoped>
- .buttonCircle {
- width: 37px;
- height: 37px;
- margin-left: 10px;
- &:last-child {
- margin-right: 10px;
- }
- }
- .addButton {
- width: 60px;
- height: 60px;
- }
- .listContent {
- border: 1px solid #F6F6FA;
- .listOfImages {
- width: 40px;
- height: 40px;
- margin-right: 10px;
- }
- }
- .headerModeuleList :deep(.van-search__content) {
- background: #fff !im\portant;
- height: 42px;
- align-items: center;
- border-radius: 6px;
- }
- </style>
|