tms 开发承运商管理模块
tms 开发承运合同模块
tms 开发承运订单模块
tms 开发承运跟踪管理模块
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ¥è¯¢å
¥åºä¿¡æ¯å表 |
| | | export const getStockInPage = (params) => { |
| | | return request({ |
| | | url: "/stockin/listPage", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // å页æ¥è¯¢æ¿è¿ååå表 |
| | | // /fakeWarehousing/list |
| | | export const getCarrierContractPage = (params) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/list", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // æ ¹æ®IDæ¥è¯¢æ¿è¿åå详æ
|
| | | // /fakeWarehousing/{id} |
| | | export const getCarrierContractDetail = (id) => { |
| | | return request({ |
| | | url: `/fakeWarehousing/${id}`, |
| | | method: "get", |
| | | }); |
| | | }; |
| | | |
| | | // æ°å¢æ¿è¿åå |
| | | // /fakeWarehousing/ |
| | | export const addCarrierContract = (data) => { |
| | | return request({ |
| | | url: "/fakeWarehousing", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | | // ä¿®æ¹æ¿è¿åå |
| | | // /fakeWarehousing/ |
| | | export const updateCarrierContract = (data) => { |
| | | return request({ |
| | | url: "/fakeWarehousing", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // æ¿è¿åå管ç-å é¤ids |
| | | // /fakeWarehousing/{ids} |
| | | export const deleteCarrierContract = (ids) => { |
| | | return request({ |
| | | url: `/fakeWarehousing/${ids}`, |
| | | method: "delete", |
| | | }); |
| | | }; |
| | | |
| | | |
| | | // å页æ¥è¯¢æ¿è¿è®¢åå表 |
| | | // /fakeWarehousing/order/list |
| | | export const getCarrierOrderPage = (params) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/order/list", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // æ ¹æ®IDæ¥è¯¢æ¿è¿è®¢å详æ
|
| | | // /fakeWarehousing/order/{id} |
| | | export const getCarrierOrderDetail = (id) => { |
| | | return request({ |
| | | url: `/fakeWarehousing/order/${id}`, |
| | | method: "get", |
| | | }); |
| | | }; |
| | | |
| | | // æ°å¢æ¿è¿è®¢å |
| | | // /fakeWarehousing/order/ |
| | | export const addCarrierOrder = (data) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/order", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | }; |
| | | |
| | | // ä¿®æ¹æ¿è¿è®¢å |
| | | // /fakeWarehousing/order/ |
| | | export const updateCarrierOrder = (data) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/order", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // å 餿¿è¿è®¢å |
| | | // /fakeWarehousing/order/{ids} |
| | | export const deleteCarrierOrder = (ids) => { |
| | | return request({ |
| | | url: `/fakeWarehousing/order/${ids}`, |
| | | method: "delete", |
| | | }); |
| | | }; |
| | | |
| | | // æ°å¢åè´§è·è¸ªè®°å½ |
| | | // /fakeWarehousing/deliveryTrack/ |
| | | export const addDeliveryTrack = (data) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/deliveryTrack", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // åè´§è·è¸ªç®¡çæ¥å£ |
| | | // å页æ¥è¯¢åè´§è·è¸ªå表 |
| | | // /fakeWarehousing/deliveryTrack/list |
| | | export const getDeliveryTrackPage = (params) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/deliveryTrack/list", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | // æ ¹æ®IDæ¥è¯¢åè´§è·è¸ªè¯¦æ
|
| | | // /fakeWarehousing/deliveryTrack/{id} |
| | | export const getDeliveryTrackDetail = (id) => { |
| | | return request({ |
| | | url: `/fakeWarehousing/deliveryTrack/${id}`, |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹åè´§è·è¸ªè®°å½ |
| | | // /fakeWarehousing/deliveryTrack/ |
| | | export const updateDeliveryTrack = (data) => { |
| | | return request({ |
| | | url: "/fakeWarehousing/deliveryTrack", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // å é¤åè´§è·è¸ªè®°å½ |
| | | // /fakeWarehousing/deliveryTrack/{ids} |
| | | export const deleteDeliveryTrack = (ids) => { |
| | | return request({ |
| | | url: `/fakeWarehousing/deliveryTrack/${ids}`, |
| | | method: "delete", |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="å
³é®å"> |
| | | <el-input |
| | | v-model="searchForm.keyword" |
| | | style="width: 240px" |
| | | placeholder="订åå·/æ¿è¿å/车ç" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="åè´§æ¥æ"> |
| | | <el-date-picker |
| | | v-model="searchForm.shipDateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | clearable |
| | | @change="changeDateRange" |
| | | @clear="clearRange" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px"> |
| | | æç´¢ |
| | | </el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="false" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total" |
| | | > |
| | | <template #statusSlot="{ row }"> |
| | | <el-tag :type="trackStatusTagType(row.trackStatus)"> |
| | | {{ trackStatusText(row.trackStatus) }} |
| | | </el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <!-- 轨迹æ¥çå¼¹çª --> |
| | | <el-dialog |
| | | v-model="trackVisible" |
| | | title="å¨é轨迹æ¥è¯¢" |
| | | width="760px" |
| | | :close-on-click-modal="false" |
| | | destroy-on-close |
| | | > |
| | | <div style="margin-bottom: 10px; color: #606266"> |
| | | <div>订åå·ï¼{{ currentRow.orderCode }}</div> |
| | | <div>æ¿è¿åï¼{{ currentRow.carrierName }}ã车çï¼{{ currentRow.vehicleNo }}</div> |
| | | <div>åè´§æ¶é´ï¼{{ currentRow.shipTime || "-" }}</div> |
| | | </div> |
| | | |
| | | <el-empty v-if="trackLoading" description="å 载轨迹ä¸..." /> |
| | | <el-empty v-else-if="trackList.length === 0" description="ææ è½¨è¿¹" /> |
| | | |
| | | <el-timeline v-else> |
| | | <el-timeline-item |
| | | v-for="item in trackList" |
| | | :key="item.id" |
| | | :timestamp="item.time" |
| | | :type="item.type" |
| | | :hollow="false" |
| | | > |
| | | <div style="font-weight: 600">{{ item.title }}</div> |
| | | <div style="color: #909399">{{ item.remark }}</div> |
| | | </el-timeline-item> |
| | | </el-timeline> |
| | | |
| | | <template #footer> |
| | | <el-button @click="trackVisible = false">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { |
| | | getDeliveryTrackPage, |
| | | getDeliveryTrackDetail, |
| | | deleteDeliveryTrack, |
| | | } from "@/api/inventoryManagement/CarrierManagement"; |
| | | |
| | | // ------------------ è½¨è¿¹ï¼ææ¶åæ°æ®ï¼çå端轨迹æ¥å£å段确å®åæ¿æ¢ï¼ ------------------ |
| | | const pad2 = (n) => String(n).padStart(2, "0"); |
| | | const formatDateTime = (d = new Date()) => { |
| | | const yyyy = d.getFullYear(); |
| | | const mm = pad2(d.getMonth() + 1); |
| | | const dd = pad2(d.getDate()); |
| | | const hh = pad2(d.getHours()); |
| | | const mi = pad2(d.getMinutes()); |
| | | const ss = pad2(d.getSeconds()); |
| | | return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`; |
| | | }; |
| | | |
| | | const trackStatusText = (s) => { |
| | | const map = { 0: "å¾
å车", 1: "è¿è¾ä¸", 2: "å·²å°è¾¾", 3: "å¼å¸¸" }; |
| | | return map[s] ?? "-"; |
| | | }; |
| | | |
| | | const trackStatusTagType = (s) => { |
| | | const map = { 0: "info", 1: "warning", 2: "success", 3: "danger" }; |
| | | return map[s] ?? "info"; |
| | | }; |
| | | |
| | | const buildMockTrack = (row) => { |
| | | const now = Date.now(); |
| | | const isArrived = Number(row.trackStatus) === 2; |
| | | const isAbnormal = Number(row.trackStatus) === 3; |
| | | |
| | | const base = [ |
| | | { |
| | | id: 1, |
| | | time: formatDateTime(new Date(now - 1000 * 60 * 60 * 18)), |
| | | title: "å·²å建åè´§å", |
| | | location: row.origin || "-", |
| | | remark: "已宿è£
车", |
| | | type: "primary", |
| | | }, |
| | | { |
| | | id: 2, |
| | | time: formatDateTime(new Date(now - 1000 * 60 * 60 * 12)), |
| | | title: "车è¾å·²å车", |
| | | location: row.origin || "-", |
| | | remark: "ä»ä»åºåºå", |
| | | type: "success", |
| | | }, |
| | | { |
| | | id: 3, |
| | | time: formatDateTime(new Date(now - 1000 * 60 * 60 * 6)), |
| | | title: isAbnormal ? "è¿è¾å¼å¸¸" : "éç»èç¹", |
| | | location: "ä¸è½¬ç«", |
| | | remark: isAbnormal ? "è½¦è¾æ
éï¼çå¾
å¤ç" : "æ£å¸¸", |
| | | type: isAbnormal ? "danger" : "warning", |
| | | }, |
| | | ]; |
| | | |
| | | if (isArrived) { |
| | | base.push({ |
| | | id: 4, |
| | | time: formatDateTime(new Date(now - 1000 * 60 * 60)), |
| | | title: "å·²å°è¾¾", |
| | | location: row.destination || "-", |
| | | remark: "å·²ç¾æ¶", |
| | | type: "success", |
| | | }); |
| | | } |
| | | |
| | | return base; |
| | | }; |
| | | |
| | | // ------------------ å表æ¥è¯¢ï¼æ¥èªå端 /fakeWarehousing/deliveryTrack/listï¼ ------------------ |
| | | // åç«¯æ ·ä¾åæ®µï¼ |
| | | // id, orderId, orderCode, carrierName, shipTime, vehicleNo, driverName, driverPhone, remark, |
| | | // createTime, updateTime, createUser, updateUser, tenantId |
| | | const normalizeRow = (raw = {}) => { |
| | | const id = raw.id ?? raw.trackId ?? raw.deliveryTrackId; |
| | | |
| | | return { |
| | | id, |
| | | orderId: raw.orderId ?? null, |
| | | orderCode: raw.orderCode ?? raw.orderNo ?? "-", |
| | | carrierName: raw.carrierName ?? raw.carrier ?? "-", |
| | | shipTime: raw.shipTime ?? raw.shipDate ?? "-", |
| | | vehicleNo: raw.vehicleNo ?? raw.carNo ?? "-", |
| | | driverName: raw.driverName ?? raw.driver ?? "-", |
| | | driverPhone: raw.driverPhone ?? raw.driverTel ?? "-", |
| | | remark: raw.remark ?? "", |
| | | createTime: raw.createTime ?? "-", |
| | | updateTime: raw.updateTime ?? raw.modifyTime ?? "-", |
| | | }; |
| | | }; |
| | | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | layout: "total, sizes, prev, pager, next, jumper", |
| | | }); |
| | | |
| | | const searchForm = reactive({ |
| | | keyword: "", |
| | | trackStatus: "", |
| | | shipDateRange: [], |
| | | shipDateStart: undefined, |
| | | shipDateEnd: undefined, |
| | | }); |
| | | |
| | | const tableColumn = ref([ |
| | | { label: "订åå·", prop: "orderCode", width: 180 }, |
| | | { label: "æ¿è¿å", prop: "carrierName", width: 180 }, |
| | | { label: "车çå·", prop: "vehicleNo", width: 130 }, |
| | | { label: "åè´§æ¶é´", prop: "shipTime", width: 170 }, |
| | | { label: "叿º", prop: "driverName", width: 120 }, |
| | | { label: "叿ºçµè¯", prop: "driverPhone", width: 140 }, |
| | | { label: "æ´æ°æ¶é´", prop: "updateTime", width: 170 }, |
| | | { |
| | | label: "æä½", |
| | | prop: "action", |
| | | dataType: "action", |
| | | fixed: "right", |
| | | width: 120, |
| | | operation: [ |
| | | { name: "æ¥ç轨迹", clickFun: (row) => openTrack(row) }, |
| | | { name: "å é¤", clickFun: (row) => handleDelete(row) }, |
| | | ], |
| | | }, |
| | | ]); |
| | | |
| | | const buildListParams = () => { |
| | | return { |
| | | current: page.current, |
| | | size: page.size, |
| | | keyword: searchForm.keyword || undefined, |
| | | orderCode: searchForm.keyword || undefined, |
| | | carrierName: searchForm.keyword || undefined, |
| | | vehicleNo: searchForm.keyword || undefined, |
| | | trackStatus: |
| | | searchForm.trackStatus === "" || searchForm.trackStatus === null || searchForm.trackStatus === undefined |
| | | ? undefined |
| | | : searchForm.trackStatus, |
| | | startDate: searchForm.shipDateStart || undefined, |
| | | endDate: searchForm.shipDateEnd || undefined, |
| | | }; |
| | | }; |
| | | |
| | | const getList = async () => { |
| | | tableLoading.value = true; |
| | | try { |
| | | const res = await getDeliveryTrackPage(buildListParams()); |
| | | const data = res?.data ?? res; |
| | | const records = data?.records ?? data?.rows ?? data?.list ?? []; |
| | | const total = data?.total ?? data?.count ?? 0; |
| | | |
| | | tableData.value = (records || []).map(normalizeRow); |
| | | page.total = total; |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "å 载失败"); |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const resetQuery = () => { |
| | | searchForm.keyword = ""; |
| | | searchForm.trackStatus = ""; |
| | | searchForm.shipDateRange = []; |
| | | searchForm.shipDateStart = undefined; |
| | | searchForm.shipDateEnd = undefined; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const changeDateRange = (date) => { |
| | | if (date && date.length === 2) { |
| | | searchForm.shipDateStart = date[0]; |
| | | searchForm.shipDateEnd = date[1]; |
| | | } else { |
| | | searchForm.shipDateStart = undefined; |
| | | searchForm.shipDateEnd = undefined; |
| | | } |
| | | getList(); |
| | | }; |
| | | |
| | | const clearRange = () => { |
| | | searchForm.shipDateRange = []; |
| | | searchForm.shipDateStart = undefined; |
| | | searchForm.shipDateEnd = undefined; |
| | | getList(); |
| | | }; |
| | | |
| | | // ------------------ 轨迹弹çªï¼è¯¦æ
è°ç¨å端 /fakeWarehousing/deliveryTrack/{id} ï¼ ------------------ |
| | | const trackVisible = ref(false); |
| | | const trackLoading = ref(false); |
| | | const trackList = ref([]); |
| | | const currentRow = reactive({}); |
| | | |
| | | const openTrack = async (row) => { |
| | | Object.assign(currentRow, row); |
| | | trackVisible.value = true; |
| | | trackLoading.value = true; |
| | | |
| | | try { |
| | | const res = await getDeliveryTrackDetail(row.id); |
| | | const detail = res?.data ?? res; |
| | | Object.assign(currentRow, normalizeRow(detail)); |
| | | |
| | | // 轨迹æç»åæ®µå°æªç¡®å®ï¼æç¨æ¨¡æè½¨è¿¹å±ç¤º |
| | | trackList.value = buildMockTrack(currentRow); |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "轨迹å 载失败"); |
| | | trackList.value = buildMockTrack(currentRow); |
| | | } finally { |
| | | trackLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // å é¤ï¼æ¹é ids åç«¯ä¹æ¯æï¼è¿éåæ¡å é¤ï¼ |
| | | const handleDelete = async (row) => { |
| | | await ElMessageBox.confirm(`确认å é¤åè´§è®°å½ã${row.orderCode || "-"}ãï¼`, "æç¤º", { |
| | | confirmButtonText: "å é¤", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }); |
| | | |
| | | tableLoading.value = true; |
| | | try { |
| | | await deleteDeliveryTrack(row.id); |
| | | ElMessage.success("å 餿å"); |
| | | |
| | | // å é¤å妿å½å页为空ååé |
| | | const res = await getDeliveryTrackPage(buildListParams()); |
| | | const data = res?.data ?? res; |
| | | const records = data?.records ?? data?.rows ?? data?.list ?? []; |
| | | if ((records || []).length === 0 && page.current > 1) { |
| | | page.current -= 1; |
| | | } |
| | | |
| | | await getList(); |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "å é¤å¤±è´¥"); |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // é¢çï¼æ°å¢/ä¿®æ¹æ¥å£å·²æ¥å
¥ï¼åç»å å¼¹çªå³å¯ï¼ |
| | | // addDeliveryTrack / updateDeliveryTrack |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="æ¿è¿å"> |
| | | <el-input |
| | | v-model="searchForm.carrierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥æ¿è¿ååç§°" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="ååç¼å·"> |
| | | <el-input |
| | | v-model="searchForm.contractCode" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥ååç¼å·" |
| | | clearable |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="ååç¶æ"> |
| | | <el-select |
| | | v-model="searchForm.contractStatus" |
| | | style="width: 160px" |
| | | placeholder="å
¨é¨" |
| | | clearable |
| | | > |
| | | <el-option label="ææ" :value="1" /> |
| | | <el-option label="æ æ" :value="0" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="ååæ¶é´"> |
| | | <el-date-picker |
| | | v-model="searchForm.timeRange" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD" |
| | | type="datetimerange" |
| | | start-placeholder="å¼å§æ¶é´" |
| | | end-placeholder="ç»ææ¶é´" |
| | | clearable |
| | | @change="changeDateRange" |
| | | @clear="clearRange" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px"> |
| | | æç´¢ |
| | | </el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="table_list"> |
| | | <div style="display: flex; justify-content: flex-end; margin-bottom: 12px"> |
| | | <el-button type="primary" @click="openCreate">å建åå</el-button> |
| | | </div> |
| | | |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="false" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total" |
| | | > |
| | | <template #statusSlot="{ row }"> |
| | | <el-tag :type="row.contractStatus === 1 ? 'success' : 'info'"> |
| | | {{ row.contractStatus === 1 ? 'ææ' : 'æ æ' }} |
| | | </el-tag> |
| | | </template> |
| | | <template #versionSlot="{ row }"> |
| | | <el-tag type="warning">v{{ row.version }}</el-tag> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <!-- å建/ç»´æ¤(ç¼è¾)å¼¹çª --> |
| | | <el-dialog |
| | | v-model="editVisible" |
| | | :title="editMode === 'create' ? 'å建æ¿è¿åå' : 'ååç»´æ¤'" |
| | | width="720px" |
| | | :close-on-click-modal="false" |
| | | destroy-on-close |
| | | > |
| | | <el-form ref="editFormRef" :model="editForm" :rules="rules" label-width="120px"> |
| | | <el-row :gutter="12"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ååç¼å·" prop="contractCode"> |
| | | <el-input v-model="editForm.contractCode" placeholder="å¦ HT-2026-0001" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åååç§°" prop="contractName"> |
| | | <el-input v-model="editForm.contractName" placeholder="å¦ éå®åå" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¿è¿ååç§°" prop="carrierName"> |
| | | <el-input v-model="editForm.carrierName" placeholder="请è¾å
¥æ¿è¿ååç§°" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ååå¼å§æ¶é´" prop="startTime"> |
| | | <el-date-picker |
| | | v-model="editForm.startTime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ååç»ææ¶é´" prop="endTime"> |
| | | <el-date-picker |
| | | v-model="editForm.endTime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetime" |
| | | placeholder="å¯é" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ååç¶æ" prop="contractStatus"> |
| | | <el-select v-model="editForm.contractStatus" placeholder="è¯·éæ©" style="width: 100%"> |
| | | <el-option label="ææ" :value="1" /> |
| | | <el-option label="æ æ" :value="0" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="editForm.remark" type="textarea" :rows="2" placeholder="å¯é" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <el-button @click="editVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" :loading="saving" @click="submitEdit">ç¡®å®</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- æ¥çå¼¹çª --> |
| | | <el-dialog v-model="viewVisible" title="ååä¿¡æ¯æ¥ç" width="720px" destroy-on-close> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="ååç¼å·">{{ viewRow.contractCode }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¿è¿å">{{ viewRow.carrierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç¶æ">{{ viewRow.contractStatus === 1 ? 'ææ' : 'æ æ' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¶é´">{{ viewRow.startTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç»ææ¶é´">{{ viewRow.endTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å建æ¶é´">{{ viewRow.createTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="ä¿®æ¹æ¶é´">{{ viewRow.updateTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="夿³¨" :span="2">{{ viewRow.remark || '-' }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <template #footer> |
| | | <el-button @click="viewVisible = false">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import dayjs from "dayjs"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { |
| | | getCarrierContractPage, |
| | | getCarrierContractDetail, |
| | | addCarrierContract, |
| | | updateCarrierContract, |
| | | deleteCarrierContract, |
| | | } from "@/api/inventoryManagement/CarrierManagement"; |
| | | |
| | | // ------------------ æ°æ®éé
ï¼å
¼å®¹å端è¿åç»æï¼ ------------------ |
| | | const normalizeRow = (raw = {}) => { |
| | | // åç«¯åæ®µï¼id/contractCode/carrierId/carrierName/contractName/contractStatus/startTime/endTime/remark/createUser/createTime/updateUser/updateTime/tenantId |
| | | return { |
| | | id: raw.id, |
| | | contractCode: raw.contractCode, |
| | | carrierId: raw.carrierId, |
| | | carrierName: raw.carrierName, |
| | | contractName: raw.contractName, |
| | | contractStatus: raw.contractStatus, |
| | | startTime: raw.startTime, |
| | | endTime: raw.endTime, |
| | | remark: raw.remark, |
| | | createUser: raw.createUser, |
| | | createTime: raw.createTime, |
| | | updateUser: raw.updateUser, |
| | | updateTime: raw.updateTime, |
| | | tenantId: raw.tenantId, |
| | | // version éåç«¯åæ®µï¼é¡µé¢å±ç¤ºå
åº |
| | | version: raw.version ?? 1, |
| | | }; |
| | | }; |
| | | |
| | | // ------------------ 页é¢ç¶æ ------------------ |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | layout: "total, sizes, prev, pager, next, jumper", |
| | | }); |
| | | |
| | | const { form: searchForm } = useFormData({ |
| | | carrierName: "", |
| | | contractCode: "", |
| | | contractName: "", |
| | | contractStatus: "", |
| | | timeRange: [], |
| | | startTime: undefined, |
| | | endTime: undefined, |
| | | }); |
| | | |
| | | const tableColumn = ref([ |
| | | { label: "ååç¼å·", prop: "contractCode", width: 160 }, |
| | | { label: "åååç§°", prop: "contractName", width: 200 }, |
| | | { label: "æ¿è¿å", prop: "carrierName", width: 200 }, |
| | | { label: "ç¶æ", prop: "contractStatus", dataType: "slot", slot: "statusSlot", width: 90 }, |
| | | { label: "å¼å§æ¶é´", prop: "startTime", width: 170 }, |
| | | { label: "ç»ææ¶é´", prop: "endTime", width: 170 }, |
| | | { label: "ä¿®æ¹æ¶é´", prop: "updateTime", width: 170 }, |
| | | { |
| | | label: "æä½", |
| | | prop: "action", |
| | | dataType: "action", |
| | | fixed: "right", |
| | | width: 140, |
| | | operation: [ |
| | | { name: "æ¥ç", clickFun: (row) => openView(row) }, |
| | | { name: "ç¼è¾", clickFun: (row) => openMaintain(row) }, |
| | | { name: "å é¤", clickFun: (row) => handleDelete(row) }, |
| | | ], |
| | | }, |
| | | ]); |
| | | |
| | | const getList = async () => { |
| | | tableLoading.value = true; |
| | | try { |
| | | const { timeRange, ...rest } = searchForm; |
| | | const params = { |
| | | ...rest, |
| | | current: page.current, |
| | | size: page.size, |
| | | }; |
| | | |
| | | const res = await getCarrierContractPage(params); |
| | | const data = res?.data ?? res; |
| | | const records = data?.records ?? data?.rows ?? data?.list ?? []; |
| | | const total = data?.total ?? data?.count ?? 0; |
| | | |
| | | tableData.value = (records || []).map(normalizeRow); |
| | | page.total = total; |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "å 载失败"); |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const resetQuery = () => { |
| | | searchForm.carrierName = ""; |
| | | searchForm.contractCode = ""; |
| | | searchForm.contractName = ""; |
| | | searchForm.contractStatus = ""; |
| | | searchForm.timeRange = []; |
| | | searchForm.startTime = undefined; |
| | | searchForm.endTime = undefined; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const changeDateRange = (date) => { |
| | | if (date && date.length === 2) { |
| | | searchForm.startTime = date[0]; |
| | | searchForm.endTime = date[1]; |
| | | } else { |
| | | searchForm.startTime = undefined; |
| | | searchForm.endTime = undefined; |
| | | } |
| | | getList(); |
| | | }; |
| | | |
| | | const clearRange = () => { |
| | | searchForm.timeRange = []; |
| | | searchForm.startTime = undefined; |
| | | searchForm.endTime = undefined; |
| | | getList(); |
| | | }; |
| | | |
| | | // ------------------ å¼¹çªï¼æ¥ç/ç»´æ¤ ------------------ |
| | | const viewVisible = ref(false); |
| | | const viewRow = reactive({}); |
| | | |
| | | const openView = async (row) => { |
| | | // å
å±ç¤ºè¡æ°æ® |
| | | Object.assign(viewRow, row); |
| | | viewVisible.value = true; |
| | | |
| | | // åæè¯¦æ
è¡¥å
¨ |
| | | if (!row?.id) return; |
| | | try { |
| | | const res = await getCarrierContractDetail(row.id); |
| | | const detail = res?.data ?? res; |
| | | Object.assign(viewRow, normalizeRow(detail)); |
| | | } catch { |
| | | // 详æ
失败ä¸é»ææ¥ç |
| | | } |
| | | }; |
| | | |
| | | const editVisible = ref(false); |
| | | const editMode = ref("create"); // create | maintain |
| | | const editFormRef = ref(); |
| | | const saving = ref(false); |
| | | const editForm = reactive({ |
| | | id: undefined, |
| | | contractCode: "", |
| | | carrierId: undefined, |
| | | carrierName: "", |
| | | contractName: "", |
| | | contractStatus: 1, |
| | | startTime: "", |
| | | endTime: "", |
| | | remark: "", |
| | | }); |
| | | |
| | | const rules = { |
| | | contractCode: [{ required: true, message: "请è¾å
¥ååç¼å·", trigger: "blur" }], |
| | | carrierName: [{ required: true, message: "请è¾å
¥æ¿è¿ååç§°", trigger: "blur" }], |
| | | contractName: [{ required: true, message: "请è¾å
¥åååç§°", trigger: "blur" }], |
| | | contractStatus: [{ required: true, message: "è¯·éæ©ååç¶æ", trigger: "change" }], |
| | | startTime: [{ required: true, message: "è¯·éæ©ååå¼å§æ¶é´", trigger: "change" }], |
| | | endTime:[{ required: true, message: "è¯·éæ©ååå¼å§æ¶é´", trigger: "change" }] |
| | | }; |
| | | |
| | | const openCreate = () => { |
| | | editMode.value = "create"; |
| | | Object.assign(editForm, { |
| | | id: undefined, |
| | | contractCode: "", |
| | | carrierId: undefined, |
| | | carrierName: "", |
| | | contractName: "", |
| | | contractStatus: 1, |
| | | startTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | endTime: "", |
| | | remark: "", |
| | | }); |
| | | editVisible.value = true; |
| | | queueMicrotask(() => editFormRef.value?.clearValidate?.()); |
| | | }; |
| | | |
| | | const openMaintain = async (row) => { |
| | | editMode.value = "maintain"; |
| | | Object.assign(editForm, { |
| | | id: row.id, |
| | | contractCode: row.contractCode, |
| | | carrierId: row.carrierId, |
| | | carrierName: row.carrierName, |
| | | contractName: row.contractName, |
| | | contractStatus: row.contractStatus, |
| | | startTime: row.startTime, |
| | | endTime: row.endTime, |
| | | remark: row.remark, |
| | | }); |
| | | |
| | | // æè¯¦æ
ï¼é¿å
åè¡¨åæ®µä¸å
¨ |
| | | if (row?.id) { |
| | | try { |
| | | const res = await getCarrierContractDetail(row.id); |
| | | const detail = res?.data ?? res; |
| | | const d = normalizeRow(detail); |
| | | Object.assign(editForm, { |
| | | id: d.id, |
| | | contractCode: d.contractCode, |
| | | carrierId: d.carrierId, |
| | | carrierName: d.carrierName, |
| | | contractName: d.contractName, |
| | | contractStatus: d.contractStatus, |
| | | startTime: d.startTime, |
| | | endTime: d.endTime, |
| | | remark: d.remark, |
| | | }); |
| | | } catch { |
| | | // ignore |
| | | } |
| | | } |
| | | |
| | | editVisible.value = true; |
| | | queueMicrotask(() => editFormRef.value?.clearValidate?.()); |
| | | }; |
| | | |
| | | const submitEdit = async () => { |
| | | saving.value = true; |
| | | try { |
| | | await editFormRef.value?.validate?.(); |
| | | |
| | | const payload = { |
| | | id: editForm.id, |
| | | contractCode: editForm.contractCode, |
| | | carrierId: editForm.carrierId, |
| | | carrierName: editForm.carrierName, |
| | | contractName: editForm.contractName, |
| | | contractStatus: editForm.contractStatus, |
| | | startTime: editForm.startTime, |
| | | endTime: editForm.endTime, |
| | | remark: editForm.remark, |
| | | }; |
| | | |
| | | if (editMode.value === "create") { |
| | | await addCarrierContract(payload); |
| | | ElMessage.success("å建æå"); |
| | | page.current = 1; |
| | | } else { |
| | | await updateCarrierContract(payload); |
| | | ElMessage.success("æ´æ°æå"); |
| | | } |
| | | |
| | | editVisible.value = false; |
| | | await getList(); |
| | | } catch (e) { |
| | | if (e?.message) ElMessage.error(e.message); |
| | | } finally { |
| | | saving.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleDelete = async (row) => { |
| | | await ElMessageBox.confirm(`确认å é¤ååã${row.contractCode}ãï¼`, "æç¤º", { |
| | | confirmButtonText: "å é¤", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }); |
| | | |
| | | tableLoading.value = true; |
| | | try { |
| | | await deleteCarrierContract(row.id); |
| | | ElMessage.success("å 餿å"); |
| | | |
| | | // å é¤åè¥å½åé¡µæ²¡æ°æ®ï¼åéä¸é¡µ |
| | | const res = await getCarrierContractPage({ |
| | | ...searchForm, |
| | | current: page.current, |
| | | size: page.size, |
| | | }); |
| | | const data = res?.data ?? res; |
| | | const records = data?.records ?? data?.rows ?? data?.list ?? []; |
| | | if ((records || []).length === 0 && page.current > 1) { |
| | | page.current -= 1; |
| | | } |
| | | |
| | | await getList(); |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "å é¤å¤±è´¥"); |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // ------------------ æ§çâçææ°çæ¬âåè½ï¼åç«¯ææ æ¥å£ï¼æä¸å¯ç¨ ------------------ |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div |
| | | class="search_form" |
| | | style=" |
| | | display: flex; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | align-items: flex-start; |
| | | " |
| | | > |
| | | <div |
| | | style=" |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 10px; |
| | | " |
| | | > |
| | | <span class="search_title">å
³é®å:</span> |
| | | <el-input |
| | | v-model="searchForm.keyword" |
| | | style="width: 240px" |
| | | placeholder="订åå·/æ¿è¿å/åè´§å°/æ¶è´§å°" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | |
| | | <span class="search_title">ç¶æ:</span> |
| | | <el-select |
| | | v-model="searchForm.orderStatus" |
| | | style="width: 160px" |
| | | clearable |
| | | placeholder="å
¨é¨" |
| | | > |
| | | <el-option label="å¾
åè´§" :value="1" /> |
| | | <el-option label="å·²åè´§" :value="2" /> |
| | | </el-select> |
| | | |
| | | <el-button type="primary" @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </div> |
| | | |
| | | <div> |
| | | <el-button type="primary" @click="openCreate">å建订å</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-row :gutter="20"> |
| | | <!-- 左侧ï¼è®¢åå表 --> |
| | | <el-col :span="24"> |
| | | <div class="table_list"> |
| | | <el-table |
| | | border |
| | | v-loading="tableLoading" |
| | | :data="tableData" |
| | | :header-cell-style="{ background: '#F0F1F5', color: '#333333' }" |
| | | height="calc(100vh - 18.5em)" |
| | | :highlight-current-row="true" |
| | | style="width: 100%" |
| | | stripe |
| | | tooltip-effect="dark" |
| | | class="lims-table" |
| | | > |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column |
| | | label="æ¿è¿è®¢åå·" |
| | | prop="orderCode" |
| | | width="160" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="æ¿è¿å" |
| | | prop="carrierName" |
| | | width="180" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åè´§å°" |
| | | prop="origin" |
| | | width="160" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="æ¶è´§å°" |
| | | prop="destination" |
| | | width="160" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="éé(kg)" |
| | | prop="weight" |
| | | width="110" |
| | | align="right" |
| | | /> |
| | | <el-table-column |
| | | label="ä½ç§¯(m³)" |
| | | prop="volume" |
| | | width="110" |
| | | align="right" |
| | | /> |
| | | <el-table-column |
| | | label="é¢è®¡è´¹ç¨(å
)" |
| | | prop="estimatedFee" |
| | | width="140" |
| | | align="right" |
| | | > |
| | | <template #default="{ row }">{{ toMoney(row.estimatedFee) }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¶æ" prop="orderStatus" width="110"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="statusTagType(row.orderStatus)"> |
| | | {{ statusText(row.orderStatus) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ´æ°æ¶é´" prop="updateTime" width="170" /> |
| | | |
| | | <el-table-column fixed="right" label="æä½" width="260" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="success" |
| | | size="small" |
| | | :disabled="scope.row.orderStatus !== 1" |
| | | @click.stop="openDelivery(scope.row)" |
| | | >åè´§</el-button |
| | | > |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | @click.stop="openView(scope.row)" |
| | | >æ¥ç</el-button |
| | | > |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | @click.stop="openEdit(scope.row)" |
| | | >ç¼è¾</el-button |
| | | > |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | size="small" |
| | | @click.stop="handleDelete(scope.row)" |
| | | >å é¤</el-button |
| | | > |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination |
| | | v-show="total > 0" |
| | | @pagination="paginationSearch" |
| | | :total="total" |
| | | :layout="page.layout" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | /> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- å建/ç¼è¾å¼¹çª --> |
| | | <el-dialog |
| | | v-model="editVisible" |
| | | :title="editMode === 'create' ? 'å建æ¿è¿è®¢å' : 'ç¼è¾æ¿è¿è®¢å'" |
| | | width="720px" |
| | | :close-on-click-modal="false" |
| | | destroy-on-close |
| | | > |
| | | <el-form |
| | | ref="editFormRef" |
| | | :model="editForm" |
| | | :rules="rules" |
| | | label-width="120px" |
| | | > |
| | | <el-row :gutter="12"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¿è¿è®¢åå·" prop="orderCode"> |
| | | <el-input |
| | | v-model="editForm.orderCode" |
| | | placeholder="å¦ TO-20260130-0001" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¿è¿ååç§°" prop="carrierName"> |
| | | <el-input |
| | | v-model="editForm.carrierName" |
| | | placeholder="请è¾å
¥æ¿è¿ååç§°" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="åè´§å°" prop="origin"> |
| | | <el-input v-model="editForm.origin" placeholder="请è¾å
¥åè´§å°" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¶è´§å°" prop="destination"> |
| | | <el-input |
| | | v-model="editForm.destination" |
| | | placeholder="请è¾å
¥æ¶è´§å°" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="éé(kg)" prop="weight"> |
| | | <el-input-number |
| | | v-model="editForm.weight" |
| | | :min="0" |
| | | :precision="2" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä½ç§¯(m³)" prop="volume"> |
| | | <el-input-number |
| | | v-model="editForm.volume" |
| | | :min="0" |
| | | :precision="3" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="é¢è®¡è´¹ç¨(å
)" prop="estimatedFee"> |
| | | <el-input-number |
| | | v-model="editForm.estimatedFee" |
| | | :min="0" |
| | | :precision="2" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input |
| | | v-model="editForm.remark" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="å¯é" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <el-button @click="editVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" :loading="saving" @click="submitEdit" |
| | | >ç¡®å®</el-button |
| | | > |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- æ¥çå¼¹çª --> |
| | | <el-dialog v-model="viewVisible" title="订åä¿¡æ¯æ¥ç" width="720px" destroy-on-close> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="æ¿è¿è®¢åå·">{{ viewRow.orderCode }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç¶æ">{{ statusText(viewRow.orderStatus) }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¿è¿å">{{ viewRow.carrierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="åè´§å°">{{ viewRow.origin }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¶è´§å°">{{ viewRow.destination }}</el-descriptions-item> |
| | | <el-descriptions-item label="éé(kg)">{{ viewRow.weight }}</el-descriptions-item> |
| | | <el-descriptions-item label="ä½ç§¯(m³)">{{ viewRow.volume }}</el-descriptions-item> |
| | | <el-descriptions-item label="é¢è®¡è´¹ç¨(å
)">{{ toMoney(viewRow.estimatedFee) }}</el-descriptions-item> |
| | | <el-descriptions-item label="å建æ¶é´">{{ viewRow.createTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ´æ°æ¶é´">{{ viewRow.updateTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="夿³¨" :span="2">{{ viewRow.remark || "-" }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <template #footer> |
| | | <el-button @click="viewVisible = false">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- åè´§å¼¹çªï¼æç¨åæäº¤ï¼çå端æ¥å£ï¼ --> |
| | | <el-dialog |
| | | v-model="deliveryVisible" |
| | | title="åè´§" |
| | | width="720px" |
| | | :close-on-click-modal="false" |
| | | destroy-on-close |
| | | > |
| | | <el-form ref="deliveryFormRef" :model="deliveryForm" :rules="deliveryRules" label-width="120px"> |
| | | <el-row :gutter="12"> |
| | | <el-col :span="24"> |
| | | <el-alert |
| | | type="info" |
| | | :closable="false" |
| | | :title="`订åå·ï¼${deliveryForm.orderCode || '-'}ï¼æ¿è¿åï¼${deliveryForm.carrierName || '-'}ï¼`" |
| | | style="margin-bottom: 12px" |
| | | /> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="åè´§æ¶é´" prop="shipTime"> |
| | | <el-date-picker |
| | | v-model="deliveryForm.shipTime" |
| | | type="datetime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | placeholder="è¯·éæ©" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="车çå·" prop="vehicleNo"> |
| | | <el-input v-model="deliveryForm.vehicleNo" placeholder="å¦ æ²ªA12345" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="叿ºå§å" prop="driverName"> |
| | | <el-input v-model="deliveryForm.driverName" placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="叿ºçµè¯" prop="driverPhone"> |
| | | <el-input v-model="deliveryForm.driverPhone" placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="deliveryForm.remark" type="textarea" :rows="2" placeholder="å¯é" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <el-button @click="deliveryVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" :loading="deliverySubmitting" @click="submitDelivery">ç¡®å®åè´§</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import dayjs from "dayjs"; |
| | | import { |
| | | getCarrierOrderPage, |
| | | getCarrierOrderDetail, |
| | | addCarrierOrder, |
| | | updateCarrierOrder, |
| | | deleteCarrierOrder, addDeliveryTrack, |
| | | } from "@/api/inventoryManagement/CarrierManagement"; |
| | | |
| | | const toMoney = (v) => { |
| | | if (v === undefined || v === null || v === "") return "0.00"; |
| | | const n = Number(v); |
| | | return Number.isFinite(n) ? n.toFixed(2) : "0.00"; |
| | | }; |
| | | |
| | | const statusText = (s) => { |
| | | const map = { |
| | | 0: "è稿", |
| | | 1: "å¾
åè´§", |
| | | 2: "å·²åè´§", |
| | | }; |
| | | return map[s] ?? "-"; |
| | | }; |
| | | |
| | | const statusTagType = (s) => { |
| | | const map = { |
| | | 0: "info", |
| | | 1: "success", |
| | | 2: "warning", |
| | | 3: "success", |
| | | 4: "danger", |
| | | }; |
| | | return map[s] ?? "info"; |
| | | }; |
| | | |
| | | // éé
å端è¿ååæ®µï¼ä½ åç«¯åæ®µæªæç»ç¡®å®æ¶å
åå
åºæ å°ï¼ |
| | | const normalizeRow = (raw = {}) => { |
| | | return { |
| | | orderId: raw.id ?? raw.orderId, |
| | | orderCode: raw.orderCode ?? raw.code, |
| | | carrierId: raw.carrierId, |
| | | carrierName: raw.carrierName, |
| | | origin: raw.origin ?? raw.startAddress ?? raw.fromAddress, |
| | | destination: raw.destination ?? raw.endAddress ?? raw.toAddress, |
| | | weight: raw.weight ?? 0, |
| | | volume: raw.volume ?? 0, |
| | | estimatedFee: raw.estimatedFee ?? raw.fee ?? 0, |
| | | orderStatus: raw.orderStatus ?? raw.status ?? 0, |
| | | remark: raw.remark ?? "", |
| | | createTime: raw.createTime, |
| | | updateTime: raw.updateTime, |
| | | }; |
| | | }; |
| | | |
| | | // ------------------ 页é¢ç¶æ ------------------ |
| | | const searchForm = reactive({ |
| | | keyword: "", |
| | | orderStatus: "", |
| | | }); |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | layout: "total, sizes, prev, pager, next, jumper", |
| | | }); |
| | | |
| | | const total = ref(0); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | const buildListParams = () => { |
| | | return { |
| | | current: page.current, |
| | | size: page.size, |
| | | keyword: searchForm.keyword || undefined, |
| | | orderCode: searchForm.keyword || undefined, |
| | | carrierName: searchForm.keyword || undefined, |
| | | origin: searchForm.keyword || undefined, |
| | | destination: searchForm.keyword || undefined, |
| | | orderStatus: |
| | | searchForm.orderStatus === "" || searchForm.orderStatus === null || searchForm.orderStatus === undefined |
| | | ? undefined |
| | | : searchForm.orderStatus, |
| | | }; |
| | | }; |
| | | |
| | | const getList = async () => { |
| | | tableLoading.value = true; |
| | | try { |
| | | const res = await getCarrierOrderPage(buildListParams()); |
| | | const data = res?.data ?? res; |
| | | const records = data?.records ?? data?.rows ?? data?.list ?? []; |
| | | const t = data?.total ?? data?.count ?? 0; |
| | | |
| | | tableData.value = (records || []).map(normalizeRow); |
| | | total.value = t; |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "å 载失败"); |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const resetQuery = () => { |
| | | searchForm.keyword = ""; |
| | | searchForm.orderStatus = ""; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationSearch = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | // ------------------ å建/ç¼è¾/æ¥ç/å é¤ ------------------ |
| | | const editVisible = ref(false); |
| | | const viewVisible = ref(false); |
| | | const editMode = ref("create"); |
| | | const saving = ref(false); |
| | | const editFormRef = ref(); |
| | | |
| | | const editForm = reactive({ |
| | | orderId: undefined, |
| | | orderCode: "", |
| | | carrierId: undefined, |
| | | carrierName: "", |
| | | origin: "", |
| | | destination: "", |
| | | weight: 0, |
| | | volume: 0, |
| | | estimatedFee: 0, |
| | | orderStatus: 0, |
| | | remark: "", |
| | | }); |
| | | |
| | | const rules = { |
| | | orderCode: [{ required: true, message: "请è¾å
¥æ¿è¿è®¢åå·", trigger: "blur" }], |
| | | carrierName: [{ required: true, message: "请è¾å
¥æ¿è¿ååç§°", trigger: "blur" }], |
| | | origin: [{ required: true, message: "请è¾å
¥åè´§å°", trigger: "blur" }], |
| | | destination: [{ required: true, message: "请è¾å
¥æ¶è´§å°", trigger: "blur" }], |
| | | }; |
| | | |
| | | const openCreate = () => { |
| | | editMode.value = "create"; |
| | | Object.assign(editForm, { |
| | | orderId: undefined, |
| | | orderCode: `TO-${dayjs().format("YYYYMMDD")}-${String(Math.floor(Math.random() * 9000 + 1000))}`, |
| | | carrierId: undefined, |
| | | carrierName: "", |
| | | origin: "", |
| | | destination: "", |
| | | weight: 0, |
| | | volume: 0, |
| | | estimatedFee: 0, |
| | | orderStatus: 0, |
| | | remark: "", |
| | | }); |
| | | editVisible.value = true; |
| | | queueMicrotask(() => editFormRef.value?.clearValidate?.()); |
| | | }; |
| | | |
| | | const openEdit = async (row) => { |
| | | editMode.value = "edit"; |
| | | Object.assign(editForm, { ...row }); |
| | | |
| | | // æè¯¦æ
è¡¥å
¨ |
| | | if (row?.id) { |
| | | try { |
| | | const res = await getCarrierOrderDetail(row.id); |
| | | const detail = res?.data ?? res; |
| | | Object.assign(editForm, normalizeRow(detail)); |
| | | } catch { |
| | | // ignore |
| | | } |
| | | } |
| | | |
| | | editVisible.value = true; |
| | | queueMicrotask(() => editFormRef.value?.clearValidate?.()); |
| | | }; |
| | | |
| | | const viewRow = reactive({}); |
| | | const openView = async (row) => { |
| | | Object.assign(viewRow, row); |
| | | viewVisible.value = true; |
| | | |
| | | if (row?.id) { |
| | | try { |
| | | const res = await getCarrierOrderDetail(row.id); |
| | | const detail = res?.data ?? res; |
| | | Object.assign(viewRow, normalizeRow(detail)); |
| | | } catch { |
| | | // ignore |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const submitEdit = async () => { |
| | | saving.value = true; |
| | | try { |
| | | await editFormRef.value?.validate?.(); |
| | | |
| | | const payload = { |
| | | id: editForm.id, |
| | | orderCode: editForm.orderCode, |
| | | carrierId: editForm.carrierId, |
| | | carrierName: editForm.carrierName, |
| | | origin: editForm.origin, |
| | | destination: editForm.destination, |
| | | weight: editForm.weight, |
| | | volume: editForm.volume, |
| | | estimatedFee: editForm.estimatedFee, |
| | | orderStatus: editForm.orderStatus, |
| | | remark: editForm.remark, |
| | | }; |
| | | |
| | | if (editMode.value === "create") { |
| | | await addCarrierOrder(payload); |
| | | ElMessage.success("å建æå"); |
| | | page.current = 1; |
| | | } else { |
| | | await updateCarrierOrder(payload); |
| | | ElMessage.success("æ´æ°æå"); |
| | | } |
| | | |
| | | editVisible.value = false; |
| | | await getList(); |
| | | } catch (e) { |
| | | if (e?.message) ElMessage.error(e.message); |
| | | } finally { |
| | | saving.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleDelete = async (row) => { |
| | | await ElMessageBox.confirm(`确认å é¤è®¢åã${row.orderCode}ãï¼`, "æç¤º", { |
| | | confirmButtonText: "å é¤", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }); |
| | | |
| | | tableLoading.value = true; |
| | | try { |
| | | await deleteCarrierOrder(row.id); |
| | | ElMessage.success("å 餿å"); |
| | | |
| | | // å é¤å妿å½åé¡µæ æ°æ®ååé |
| | | const res = await getCarrierOrderPage(buildListParams()); |
| | | const data = res?.data ?? res; |
| | | const records = data?.records ?? data?.rows ?? data?.list ?? []; |
| | | if ((records || []).length === 0 && page.current > 1) { |
| | | page.current -= 1; |
| | | } |
| | | |
| | | await getList(); |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "å é¤å¤±è´¥"); |
| | | } finally { |
| | | tableLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // ------------------ åè´§ï¼æç¨åæäº¤ï¼çå端æ¥å£ï¼ ------------------ |
| | | const deliveryVisible = ref(false); |
| | | const deliverySubmitting = ref(false); |
| | | const deliveryFormRef = ref(); |
| | | const deliveryForm = reactive({ |
| | | orderId: undefined, |
| | | orderCode: "", |
| | | carrierName: "", |
| | | shipTime: "", |
| | | vehicleNo: "", |
| | | driverName: "", |
| | | driverPhone: "", |
| | | remark: "", |
| | | }); |
| | | |
| | | const deliveryRules = { |
| | | shipTime: [{ required: true, message: "è¯·éæ©åè´§æ¶é´", trigger: "change" }], |
| | | vehicleNo: [{ required: true, message: "请è¾å
¥è½¦çå·", trigger: "blur" }], |
| | | }; |
| | | |
| | | const openDelivery = (row) => { |
| | | console.log(row) |
| | | Object.assign(deliveryForm, { |
| | | orderId: row.id || row.orderId, |
| | | orderCode: row.orderCode, |
| | | carrierName: row.carrierName, |
| | | shipTime: dayjs().format("YYYY-MM-DD HH:mm:ss"), |
| | | vehicleNo: "", |
| | | driverName: "", |
| | | driverPhone: "", |
| | | remark: "", |
| | | }); |
| | | |
| | | deliveryVisible.value = true; |
| | | queueMicrotask(() => deliveryFormRef.value?.clearValidate?.()); |
| | | }; |
| | | |
| | | const submitDelivery = async () => { |
| | | deliverySubmitting.value = true; |
| | | try { |
| | | await deliveryFormRef.value?.validate?.(); |
| | | console.log(deliveryForm) |
| | | let res = await addDeliveryTrack(deliveryForm) |
| | | if(res?.data){ |
| | | ElMessage.success("æäº¤æå"); |
| | | } |
| | | |
| | | deliveryVisible.value = false; |
| | | await getList(); |
| | | } catch (e) { |
| | | ElMessage.error(e?.message || e?.msg || "æäº¤å¤±è´¥"); |
| | | } finally { |
| | | deliverySubmitting.value = false; |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-form :model="form"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´ååå·ï¼"> |
| | | <el-tag size="large">{{ form.purchaseContractNumber }}</el-tag> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼"> |
| | | <el-text>{{ form.salesContractNo }}</el-text> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨åä»·(å
)ï¼"> |
| | | <el-text type="primary">{{ form.taxInclusiveUnitPrice }}</el-text> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å建æ¶é´ï¼"> |
| | | <el-text>{{ form.createdAt }}</el-text> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å票å·ï¼"> |
| | | <el-input v-model="form.invoiceNumber" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ç¥¨æ°ï¼"> |
| | | <el-input-number :step="0.1" :min="0" style="width: 100%" v-model="form.ticketsNum" @change="inputTicketsNum" :precision="2"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¬æ¬¡æ¥ç¥¨éé¢(å
)ï¼"> |
| | | <el-input-number :step="0.1" :min="0" style="width: 100%" v-model="form.ticketsAmount" @change="inputTicketsAmount" :precision="2"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æªæ¥ç¥¨æ°ï¼"> |
| | | <el-text type="success">{{ form.futureTickets }}</el-text> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getProductRecordById } from "@/api/procurementManagement/procurementInvoiceLedger"; |
| | | const { proxy } = getCurrentInstance() |
| | | |
| | | defineOptions({ |
| | | name: "æ¥ç¥¨å°è´¦è¡¨å", |
| | | }); |
| | | const temFutureTickets = ref(0) // åå§æªæ¥ç¥¨æ° |
| | | const initialTicketsNum = ref(0) // åå§æ¥ç¥¨æ° |
| | | const initialTicketsAmount = ref(0) // åå§æ¥ç¥¨éé¢ |
| | | const quantity = ref(0) // æ»æ°é |
| | | const { form, resetForm } = useFormData({ |
| | | id: undefined, |
| | | purchaseContractNumber: undefined, // éè´ååå· |
| | | salesContractNo: undefined, // éå®ååå· |
| | | createdAt: undefined, // å建æ¶é´ |
| | | invoiceNumber: undefined, // åç¥¨å· |
| | | ticketsNum: undefined, // æ¥ç¥¨æ° |
| | | ticketsAmount: undefined, // æ¥ç¥¨éé¢ |
| | | taxInclusiveUnitPrice: undefined, // å«ç¨åä»· |
| | | ticketRegistrationId: undefined, // å«ç¨åä»· |
| | | }); |
| | | |
| | | const load = async (id) => { |
| | | const { code, data } = await getProductRecordById({ id }); |
| | | if (code === 200) { |
| | | form.id = data.id; |
| | | form.purchaseContractNumber = data.purchaseContractNumber; |
| | | form.salesContractNo = data.salesContractNo; |
| | | form.createdAt = data.createdAt; |
| | | form.invoiceNumber = data.invoiceNumber; |
| | | form.ticketsNum = data.ticketsNum; |
| | | form.ticketsAmount = data.ticketsAmount ? Number(data.ticketsAmount).toFixed(2) : 0; |
| | | form.taxInclusiveUnitPrice = data.taxInclusiveUnitPrice; |
| | | form.futureTickets = data.futureTickets; |
| | | temFutureTickets.value = data.futureTickets; |
| | | initialTicketsNum.value = data.ticketsNum || 0; |
| | | initialTicketsAmount.value = data.ticketsAmount || 0; |
| | | form.ticketRegistrationId = data.ticketRegistrationId; |
| | | // è·åæ»æ°éï¼å¦ææ°æ®ä¸æ quantity åæ®µå使ç¨ï¼å¦åä½¿ç¨æ¥ç¥¨æ°+æªæ¥ç¥¨æ° |
| | | quantity.value = data.quantity || (Number(data.ticketsNum || 0) + Number(data.futureTickets || 0)); |
| | | } |
| | | }; |
| | | |
| | | const inputTicketsNum = (val) => { |
| | | // ç¡®ä¿å«ç¨åä»·åå¨ä¸ä¸ä¸ºé¶ |
| | | if (!form.taxInclusiveUnitPrice || Number(form.taxInclusiveUnitPrice) === 0) { |
| | | proxy.$modal.msgWarning("å«ç¨åä»·ä¸è½ä¸ºé¶ææªå®ä¹"); |
| | | return; |
| | | } |
| | | |
| | | const newTicketsNum = Number(form.ticketsNum) || 0; |
| | | const currentTicketsNum = Number(initialTicketsNum.value) || 0; |
| | | |
| | | // è®¡ç®æ°å¢çæ¥ç¥¨æ° |
| | | const addedTicketsNum = newTicketsNum - currentTicketsNum; |
| | | |
| | | // è®¡ç®æ°çæªæ¥ç¥¨æ° = åå§æªæ¥ç¥¨æ° - æ°å¢çæ¥ç¥¨æ° |
| | | const newFutureTickets = Number(temFutureTickets.value) - addedTicketsNum; |
| | | |
| | | // éªè¯ï¼æ°çæ¥ç¥¨æ° + æ°çæªæ¥ç¥¨æ° ⤠quantity |
| | | if (newTicketsNum + newFutureTickets > Number(quantity.value)) { |
| | | proxy.$modal.msgWarning(`æ¥ç¥¨æ°+æªæ¥ç¥¨æ°ä¸è½å¤§äºæ»æ°é(${quantity.value})`); |
| | | // éå¶æ¥ç¥¨æ°ï¼ä½¿å
¶æ»¡è¶³ï¼æ¥ç¥¨æ° + æªæ¥ç¥¨æ° ⤠quantity |
| | | // æå¤§æ¥ç¥¨æ° = quantity - åå§æªæ¥ç¥¨æ° + åå§æ¥ç¥¨æ° |
| | | const maxTicketsNum = Number(quantity.value) - Number(temFutureTickets.value) + Number(initialTicketsNum.value); |
| | | form.ticketsNum = Math.max(0, Math.min(maxTicketsNum, newTicketsNum)); |
| | | // éæ°è®¡ç® |
| | | const recalculatedAddedTicketsNum = Number(form.ticketsNum) - Number(initialTicketsNum.value); |
| | | const recalculatedFutureTickets = Number(temFutureTickets.value) - recalculatedAddedTicketsNum; |
| | | form.futureTickets = Number(recalculatedFutureTickets.toFixed(2)); |
| | | const ticketsAmount = Number(form.ticketsNum) * Number(form.taxInclusiveUnitPrice); |
| | | form.ticketsAmount = Number(ticketsAmount.toFixed(2)); |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥æ°å¢çæ¥ç¥¨æ°æ¯å¦å¤§äºåå§æªæ¥ç¥¨æ° |
| | | if (addedTicketsNum > Number(temFutureTickets.value)) { |
| | | proxy.$modal.msgWarning("æ°å¢å¼ç¥¨æ°ä¸å¾å¤§äºæªå¼ç¥¨æ°"); |
| | | form.ticketsNum = Number(initialTicketsNum.value) + Number(temFutureTickets.value); |
| | | } |
| | | |
| | | // ç¡®ä¿æææ°å¼é½è½¬æ¢ä¸ºæ°åç±»åè¿è¡è®¡ç® |
| | | const finalTicketsNum = Number(form.ticketsNum) || 0; |
| | | const finalAddedTicketsNum = finalTicketsNum - Number(initialTicketsNum.value); |
| | | const finalFutureTickets = Number(temFutureTickets.value) - finalAddedTicketsNum; |
| | | const ticketsAmount = finalTicketsNum * Number(form.taxInclusiveUnitPrice); |
| | | form.futureTickets = Number(finalFutureTickets.toFixed(2)); |
| | | form.ticketsAmount = Number(ticketsAmount.toFixed(2)); |
| | | }; |
| | | const inputTicketsAmount = (val) => { |
| | | // ç¡®ä¿å«ç¨åä»·åå¨ä¸ä¸ä¸ºé¶ |
| | | if (!form.taxInclusiveUnitPrice || Number(form.taxInclusiveUnitPrice) === 0) { |
| | | proxy.$modal.msgWarning("å«ç¨åä»·ä¸è½ä¸ºé¶ææªå®ä¹"); |
| | | return; |
| | | } |
| | | |
| | | const newTicketsAmount = Number(val) || 0; |
| | | |
| | | // è®¡ç®æ°çæ¥ç¥¨æ° |
| | | const newTicketsNum = newTicketsAmount / Number(form.taxInclusiveUnitPrice); |
| | | const currentTicketsNum = Number(initialTicketsNum.value) || 0; |
| | | |
| | | // è®¡ç®æ°å¢çæ¥ç¥¨æ° |
| | | const addedTicketsNum = newTicketsNum - currentTicketsNum; |
| | | |
| | | // è®¡ç®æ°çæªæ¥ç¥¨æ° = åå§æªæ¥ç¥¨æ° - æ°å¢çæ¥ç¥¨æ° |
| | | const newFutureTickets = Number(temFutureTickets.value) - addedTicketsNum; |
| | | |
| | | // éªè¯ï¼æ°çæ¥ç¥¨æ° + æ°çæªæ¥ç¥¨æ° ⤠quantity |
| | | if (newTicketsNum + newFutureTickets > Number(quantity.value)) { |
| | | proxy.$modal.msgWarning(`æ¥ç¥¨æ°+æªæ¥ç¥¨æ°ä¸è½å¤§äºæ»æ°é(${quantity.value})`); |
| | | // éå¶æ¥ç¥¨æ°ï¼ä½¿å
¶æ»¡è¶³ï¼æ¥ç¥¨æ° + æªæ¥ç¥¨æ° ⤠quantity |
| | | const maxTicketsNum = Number(quantity.value) - Number(temFutureTickets.value) + Number(initialTicketsNum.value); |
| | | form.ticketsNum = Math.max(0, Math.min(maxTicketsNum, newTicketsNum)); |
| | | form.ticketsAmount = Number((form.ticketsNum * Number(form.taxInclusiveUnitPrice)).toFixed(2)); |
| | | const recalculatedAddedTicketsNum = Number(form.ticketsNum) - Number(initialTicketsNum.value); |
| | | const recalculatedFutureTickets = Number(temFutureTickets.value) - recalculatedAddedTicketsNum; |
| | | form.futureTickets = Number(recalculatedFutureTickets.toFixed(2)); |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥æ°å¢çæ¥ç¥¨é颿¯å¦å¤§äºåå§æªæ¥ç¥¨æ°å¯¹åºçéé¢ |
| | | const maxAddedAmount = Number(temFutureTickets.value * form.taxInclusiveUnitPrice); |
| | | if (addedTicketsNum > 0 && addedTicketsNum * Number(form.taxInclusiveUnitPrice) > maxAddedAmount) { |
| | | proxy.$modal.msgWarning("æ°å¢æ¥ç¥¨éé¢ä¸å¾å¤§äºæªå¼ç¥¨éé¢"); |
| | | form.ticketsAmount = Number((initialTicketsAmount.value + maxAddedAmount).toFixed(2)); |
| | | form.ticketsNum = Number((currentTicketsNum + Number(temFutureTickets.value)).toFixed(2)); |
| | | form.futureTickets = 0; |
| | | return; |
| | | } |
| | | |
| | | // ç¡®ä¿æææ°å¼é½è½¬æ¢ä¸ºæ°åç±»åè¿è¡è®¡ç® |
| | | const finalTicketsNum = Number(newTicketsNum.toFixed(2)); |
| | | const finalAddedTicketsNum = finalTicketsNum - Number(initialTicketsNum.value); |
| | | const finalFutureTickets = Number(temFutureTickets.value) - finalAddedTicketsNum; |
| | | form.ticketsNum = finalTicketsNum; |
| | | form.futureTickets = Number(finalFutureTickets.toFixed(2)); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | load, |
| | | form, |
| | | resetForm, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog :title="modalOptions.title" v-model="visible" @close="close"> |
| | | <EditForm ref="editFormRef" /> |
| | | <template #footer> |
| | | <el-button type="primary" :loading="loading" @click="sendForm"> |
| | | {{ modalOptions.confirmText }} |
| | | </el-button> |
| | | <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { useModal } from "@/hooks/useModal"; |
| | | import EditForm from "../Form/EditForm.vue"; |
| | | import { updateRegistration } from "@/api/procurementManagement/procurementInvoiceLedger"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | defineOptions({ |
| | | name: "æ¥ç¥¨å°è´¦ç¼è¾", |
| | | }); |
| | | const emits = defineEmits(["success"]); |
| | | |
| | | const saleLedgerProjectId = ref('') |
| | | const editFormRef = ref(); |
| | | const { |
| | | id, |
| | | visible, |
| | | loading, |
| | | openModal, |
| | | modalOptions, |
| | | handleConfirm, |
| | | closeModal, |
| | | } = useModal({ title: "æ¥ç¥¨å°è´¦" }); |
| | | |
| | | const open = async (row) => { |
| | | openModal(row.id); |
| | | saleLedgerProjectId.value = row.saleLedgerProjectId; |
| | | await nextTick(); |
| | | editFormRef.value.load(row.id); |
| | | }; |
| | | |
| | | const close = () => { |
| | | editFormRef.value.resetForm(); |
| | | closeModal(); |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | const form = editFormRef.value.form; |
| | | form.saleLedgerProjectId = saleLedgerProjectId.value; |
| | | const { code } = await updateRegistration(form); |
| | | if (code === 200) { |
| | | emits("success"); |
| | | ElMessage({ message: "æä½æå", type: "success" }); |
| | | close(); |
| | | } |
| | | }; |
| | | |
| | | defineExpose({ |
| | | open, |
| | | }); |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="upload.open" :title="upload.title" :width="500"> |
| | | <FileUpload |
| | | ref="fileUploadRef" |
| | | accept=".xlsx, .xls, .pdf" |
| | | :headers="upload.headers" |
| | | :autoUpload="true" |
| | | :action="upload.url" |
| | | :disabled="upload.isUploading" |
| | | :showTip="false" |
| | | :limit="10" |
| | | @success="handleFileSuccess" |
| | | @remove="removeFile" |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { reactive } from "vue"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import { FileUpload } from "@/components/Upload"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { ref } from "vue"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | |
| | | defineOptions({ |
| | | name: "æ¥ç¥¨å°è´¦éä»¶è¡¥å
", |
| | | }); |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | id: undefined, |
| | | tempFileIds: [], |
| | | }); |
| | | const emits = defineEmits(["uploadSuccess"]); |
| | | const fileUploadRef = ref(); |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼ä¾åºå导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼ä¾åºå导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/file/upload", |
| | | }); |
| | | // ç¹å»å¯¼å
¥ |
| | | const handleImport = (id) => { |
| | | form.id = id; |
| | | upload.open = true; |
| | | upload.title = "æ¥ç¥¨å°è´¦éä»¶è¡¥å
"; |
| | | }; |
| | | |
| | | const submitFileForm = () => { |
| | | emits("uploadSuccess", form); |
| | | resetForm(); |
| | | upload.open = false; |
| | | // æ¸
空æä»¶å表 |
| | | fileUploadRef.value.fileList = []; |
| | | }; |
| | | |
| | | const handleFileSuccess = (response) => { |
| | | if (response.code == 200) { |
| | | form.tempFileIds.push(response.data.tempId); |
| | | console.log('form',form); |
| | | ElMessage({ message: "导å
¥æå", type: "success" }); |
| | | } else { |
| | | ElMessage({ message: response.msg, type: "error" }); |
| | | } |
| | | }; |
| | | |
| | | const removeFile = (file) => { |
| | | const { tempId } = file.response.data; |
| | | form.tempFileIds = form.tempFileIds.filter((item) => item !== tempId); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | handleImport, |
| | | }); |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="éè´ååå·"> |
| | | <el-input |
| | | v-model="filters.purchaseContractNumber" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¾åºå"> |
| | | <el-input |
| | | v-model="filters.supplierName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¥ç¥¨æ¥æ"> |
| | | <el-date-picker |
| | | style="width: 240px" |
| | | v-model="filters.createdAt" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | start-placeholder="å¼å§æ¶é´" |
| | | end-placeholder="ç»ææ¶é´" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button @click="resetFilters"> éç½® </el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableLoading="loading" |
| | | :tableData="dataList" |
| | | :isSelection="true" |
| | | height="calc(100vh - 19.5em)" |
| | | :isShowSummary="true" |
| | | :summaryMethod="summarizeMainTable" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | <template #commonFilesRef="{ row }"> |
| | | <el-dropdown @command="(command) => handleCommand(command, row)"> |
| | | <el-button link :icon="Files" type="danger"> éä»¶ </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item |
| | | v-if="row.commonFiles.length !== 0" |
| | | :icon="Download" |
| | | command="download" |
| | | > |
| | | ä¸è½½ |
| | | </el-dropdown-item> |
| | | <el-dropdown-item :icon="Upload" command="upload"> |
| | | ä¸ä¼ |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button |
| | | type="primary" |
| | | text |
| | | @click="openEdit(row)" |
| | | :disabled="row.issUerId !== userStore.id" |
| | | > |
| | | ç¼è¾ |
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | text |
| | | :disabled="row.issUerId !== userStore.id" |
| | | @click="handleDelete(row)" |
| | | > |
| | | å é¤ |
| | | </el-button> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <UploadModal ref="modalRef" @uploadSuccess="uploadSuccess"></UploadModal> |
| | | <EditModal ref="editmodalRef" @success="getTableData"></EditModal> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, getCurrentInstance } from "vue"; |
| | | import { usePaginationApi } from "@/hooks/usePaginationApi"; |
| | | import { |
| | | Files, |
| | | Download, |
| | | Search, |
| | | Upload, |
| | | EditPen, |
| | | } from "@element-plus/icons-vue"; |
| | | import { |
| | | delRegistration, |
| | | productRecordPage, |
| | | productUploadFile, |
| | | } from "@/api/procurementManagement/procurementInvoiceLedger.js"; |
| | | import { onMounted } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import UploadModal from "./Modal/UploadModal.vue"; |
| | | import EditModal from "./Modal/EditModal.vue"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import {delInvoiceLedgerByRegProductId} from "@/api/salesManagement/invoiceLedger.js"; |
| | | const userStore = useUserStore(); |
| | | |
| | | defineOptions({ |
| | | name: "æ¥ç¥¨å°è´¦", |
| | | }); |
| | | |
| | | const modalRef = ref(); |
| | | const editmodalRef = ref(); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const multipleVal = ref([]); |
| | | const { |
| | | loading, |
| | | filters, |
| | | columns, |
| | | dataList, |
| | | pagination, |
| | | getTableData, |
| | | resetFilters, |
| | | onCurrentChange, |
| | | } = usePaginationApi( |
| | | productRecordPage, |
| | | { |
| | | purchaseContractNumber: undefined, // éè´ååå· |
| | | supplierName: undefined, // ä¾åºå |
| | | createdAt: [], // æ¥ç¥¨æ¥æ |
| | | }, |
| | | [ |
| | | { |
| | | label: "éè´ååå·", |
| | | prop: "purchaseContractNumber", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "éå®ååå·", |
| | | prop: "salesContractNo", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "项ç®åç§°", |
| | | prop: "projectName", |
| | | width: 240, |
| | | }, |
| | | { |
| | | label: "ä¾åºååç§°", |
| | | prop: "supplierName", |
| | | width: 240, |
| | | }, |
| | | { |
| | | label: "产å大类", |
| | | prop: "productCategory", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | | prop: "specificationModel", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "å票å·", |
| | | prop: "invoiceNumber", |
| | | width: 200, |
| | | }, |
| | | { |
| | | label: "ååéé¢(å
)", |
| | | prop: "taxInclusiveTotalPrice", |
| | | width: 200, |
| | | formatData: (cell) => { |
| | | return cell ? parseFloat(cell).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | { |
| | | label: "æ¬æ¬¡æ¥ç¥¨æ°", |
| | | prop: "ticketsNum", |
| | | width: 110, |
| | | }, |
| | | { |
| | | label: "æ¥ç¥¨æ¥æ", |
| | | prop: "createdAt", |
| | | width: 110, |
| | | }, |
| | | { |
| | | label: "æ¥ç¥¨éé¢(å
)", |
| | | prop: "ticketsAmount", |
| | | width: 200, |
| | | formatData: (cell) => { |
| | | return cell ? parseFloat(cell).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | { |
| | | label: "ä¸å«ç¨éé¢", |
| | | prop: "unTicketsPrice", |
| | | width: 200, |
| | | formatData: (cell) => { |
| | | return cell ? parseFloat(cell).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | { |
| | | label: "å¢å¼ç¨", |
| | | prop: "invoiceAmount", |
| | | width: 200, |
| | | }, |
| | | { |
| | | label: "å½å
¥äºº", |
| | | prop: "issUer", |
| | | width: 200, |
| | | }, |
| | | { |
| | | label: "éä»¶", |
| | | align: "center", |
| | | prop: "commonFiles", |
| | | dataType: "slot", |
| | | fixed: "right", |
| | | slot: "commonFilesRef", |
| | | width: 120, |
| | | }, |
| | | { |
| | | fixed: "right", |
| | | width: 150, |
| | | label: "æä½", |
| | | dataType: "slot", |
| | | slot: "operation", |
| | | align: "center", |
| | | }, |
| | | ], |
| | | {}, |
| | | { |
| | | createdAt: (aim) => ({ |
| | | createdAtStart: aim ? aim[0] : undefined, |
| | | createdAtEnd: aim ? aim[1] : undefined, |
| | | }), |
| | | } |
| | | ); |
| | | |
| | | // 主表åè®¡æ¹æ³ |
| | | const summarizeMainTable = (param) => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "taxInclusiveTotalPrice", |
| | | "ticketsAmount", |
| | | "unTicketsPrice", |
| | | "invoiceAmount", |
| | | ], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | } |
| | | ); |
| | | }; |
| | | |
| | | const handleSelectionChange = (val) => { |
| | | multipleVal.value = val; |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/purchase/registration/export", {}, "æ¥ç¥¨ç»è®°.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const handleFiles = (fileList) => { |
| | | fileList.forEach((e) => { |
| | | proxy.$download.name(e.url); |
| | | }); |
| | | }; |
| | | |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | onCurrentChange(page); |
| | | }; |
| | | |
| | | const handleCommand = (command, row) => { |
| | | switch (command) { |
| | | case "download": |
| | | handleFiles(row.commonFiles); |
| | | break; |
| | | case "upload": |
| | | console.log(row.commonFiles); |
| | | openUoload(row.ticketRegistrationId); |
| | | break; |
| | | } |
| | | }; |
| | | |
| | | const openUoload = (id) => { |
| | | modalRef.value.handleImport(id); |
| | | }; |
| | | |
| | | const openEdit = (row) => { |
| | | editmodalRef.value.open(row); |
| | | }; |
| | | |
| | | // ä¸ä¼ æåååä»ä¹ |
| | | const uploadSuccess = async (data) => { |
| | | const { code } = await productUploadFile({ |
| | | ticketRegistrationId: data.id, |
| | | tempFileIds: data.tempFileIds, |
| | | }); |
| | | if (code === 200) { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | getTableData(); |
| | | } |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = (row) => { |
| | | let ids = []; |
| | | ids.push(row.id); |
| | | ElMessageBox.confirm("该å¼ç¥¨å°è´¦å°è¢«å é¤,æ¯å¦ç¡®è®¤å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | loading.value = true; |
| | | delRegistration(ids).then((res) => { |
| | | getTableData(); |
| | | }); |
| | | loading.value = false; |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | .tagBox { |
| | | margin-top: 4px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">éè´ååå·ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.purchaseContractNumber" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <span class="search_title" style="margin-left: 10px">ä¾åºåï¼</span> |
| | | <el-input |
| | | v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <span class="search_title" style="margin-left: 10px">æ¥ç¥¨æ¥æï¼</span> |
| | | <el-date-picker |
| | | style="width: 240px" |
| | | v-model="searchForm.issueDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | start-placeholder="å¼å§æ¶é´" |
| | | end-placeholder="ç»ææ¶é´" |
| | | clearable |
| | | @change="changeDateRange" |
| | | @clear="clearRange" |
| | | /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row) => row.id" |
| | | show-summary |
| | | :summary-method="summarizeMainTable" |
| | | @expand-change="expandChange" |
| | | height="calc(100vh - 18.5em)" |
| | | stripe |
| | | > |
| | | <el-table-column align="center" label="åºå·" type="index" width="55" /> |
| | | <el-table-column type="expand"> |
| | | <template #default="props"> |
| | | <el-table |
| | | :data="props.row.children" |
| | | border |
| | | show-summary |
| | | :summary-method="summarizeChildrenTable" |
| | | stripe |
| | | > |
| | | <el-table-column |
| | | align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" |
| | | /> |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" /> |
| | | <el-table-column label="æ°é" prop="quantity" /> |
| | | <el-table-column label="ç¨ç(%)" prop="taxRate" /> |
| | | <el-table-column |
| | | label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column |
| | | label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column |
| | | label="ä¸å«ç¨æ»ä»·(å
)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column label="æ¬æ¬¡æ¥ç¥¨æ°" prop="ticketsNum" /> |
| | | <el-table-column |
| | | label="æ¬æ¬¡æ¥ç¥¨éé¢(å
)" |
| | | prop="ticketsAmount" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column label="æªæ¥ç¥¨æ°" prop="futureTickets" /> |
| | | <el-table-column |
| | | label="æªæ¥ç¥¨éé¢(å
)" |
| | | prop="futureTicketsAmount" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | </el-table> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="éè´ååå·" |
| | | prop="purchaseContractNumber" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="éå®ååå·" |
| | | prop="salesContractNo" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="ä¾åºååç§°" |
| | | prop="supplierName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="å票å·" |
| | | prop="invoiceNumber" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="ååéé¢(å
)" |
| | | prop="invoiceAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column label="å¼ç¥¨äºº" prop="issUer" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="å¼ç¥¨æ¥æ" |
| | | prop="issueDate" |
| | | show-overflow-tooltip |
| | | /> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | @pagination="paginationChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | invoiceListPage, |
| | | productRecordList, |
| | | } from "@/api/procurementManagement/procurementInvoiceLedger.js"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const data = reactive({ |
| | | searchForm: { |
| | | purchaseContractNumber: "", |
| | | supplierName: "", |
| | | issueDate: [ |
| | | dayjs().startOf("month").format("YYYY-MM-DD"), |
| | | dayjs().endOf("month").format("YYYY-MM-DD"), |
| | | ], |
| | | issueDateStart: dayjs().startOf("month").format("YYYY-MM-DD"), |
| | | issueDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"), |
| | | }, |
| | | form: { |
| | | issueDate: "", // å¼ç¥¨æ¥æ |
| | | purchaseLedgerId: "", |
| | | purchaseLedgerNo: "", |
| | | issUerId: "", // å¼ç¥¨äººid |
| | | issUer: "", // å¼ç¥¨äººå§å |
| | | }, |
| | | rules: { |
| | | purchaseLedgerId: [ |
| | | { required: true, message: "è¯·éæ©", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const { issueDate, ...rest } = searchForm.value; |
| | | invoiceListPage({ ...rest, ...page }) |
| | | .then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.records; |
| | | tableData.value.map((item) => { |
| | | item.children = []; |
| | | }); |
| | | total.value = res.total; |
| | | expandedRowKeys.value = []; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const expandedRowKeys = ref([]); |
| | | // å±å¼è¡ |
| | | const expandChange = (row, expandedRows) => { |
| | | if (expandedRows.length > 0) { |
| | | expandedRowKeys.value = []; |
| | | try { |
| | | productRecordList({ id: row.id }).then((res) => { |
| | | const index = tableData.value.findIndex((item) => item.id === row.id); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res; |
| | | } |
| | | expandedRowKeys.value.push(row.id); |
| | | }); |
| | | } catch (error) { |
| | | console.log(error); |
| | | } |
| | | } else { |
| | | expandedRowKeys.value = []; |
| | | } |
| | | }; |
| | | // 主表åè®¡æ¹æ³ |
| | | const summarizeMainTable = (param) => { |
| | | return proxy.summarizeTable(param, ["invoiceAmount"], { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | }); |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeChildrenTable = (param) => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | "ticketsNum", |
| | | "ticketsAmount", |
| | | "futureTickets", |
| | | "futureTicketsAmount", |
| | | ], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | } |
| | | ); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/purchase/registration/export", {}, "æ¥ç¥¨ç»è®°.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const changeDateRange = (date) => { |
| | | if (date) { |
| | | searchForm.value.receiptPaymentDateStart = date[0]; |
| | | searchForm.value.receiptPaymentDateEnd = date[1]; |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | const clearRange = () => { |
| | | searchForm.value.issueDate = []; |
| | | searchForm.value.issueDateStart = undefined; |
| | | searchForm.value.issueDateEnd = undefined; |
| | | getList(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="dialogVisible" title="éä»¶" width="40%" :before-close="handleClose"> |
| | | <el-table :data="tableData" border height="40vh"> |
| | | <el-table-column label="éä»¶åç§°" prop="name" min-width="400" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="150" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">ä¸è½½</el-button> |
| | | <el-button link type="primary" size="small" @click="lookFile(scope.row)">é¢è§</el-button> |
| | | <el-button link type="danger" size="small" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import { ElMessageBox, ElMessage } from 'element-plus' |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | import { delCommonFile } from '@/api/publicApi/commonFile.js' |
| | | |
| | | const dialogVisible = ref(false) |
| | | const tableData = ref([]) |
| | | const { proxy } = getCurrentInstance(); |
| | | const filePreviewRef = ref() |
| | | const handleClose = () => { |
| | | dialogVisible.value = false |
| | | } |
| | | const open = (list) => { |
| | | dialogVisible.value = true |
| | | tableData.value = list |
| | | } |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | |
| | | } |
| | | const lookFile = (row) => { |
| | | filePreviewRef.value.open(row.url) |
| | | } |
| | | // å é¤éä»¶ |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm(`确认å é¤éä»¶"${row.name}"åï¼`, 'å é¤ç¡®è®¤', { |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning', |
| | | }).then(() => { |
| | | delCommonFile([row.id]).then(() => { |
| | | ElMessage.success('å 餿å') |
| | | // ä»å表ä¸ç§»é¤å·²å é¤çéä»¶ |
| | | const index = tableData.value.findIndex(item => item.id === row.id) |
| | | if (index !== -1) { |
| | | tableData.value.splice(index, 1) |
| | | } |
| | | }).catch(() => { |
| | | ElMessage.error('å é¤å¤±è´¥') |
| | | }) |
| | | }).catch(() => { |
| | | proxy.$modal.msg('已忶å é¤') |
| | | }) |
| | | } |
| | | defineExpose({ |
| | | open |
| | | }) |
| | | </script> |
| | | |
| | | <style></style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">æ¿è¿åæ¡£æ¡ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥æ¿è¿ååç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')" |
| | | >æ°å¢æ¿è¿å</el-button |
| | | > |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="info" plain icon="Upload" @click="handleImport" |
| | | >导å
¥</el-button |
| | | > |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | </div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢æ¿è¿åä¿¡æ¯' : 'ç¼è¾æ¿è¿åä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia" |
| | | > |
| | | <el-form |
| | | :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¿è¿ååç§°ï¼" prop="supplierName"> |
| | | <el-input |
| | | v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item |
| | | label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum" |
| | | > |
| | | <el-input |
| | | v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸å°åï¼" prop="companyAddress"> |
| | | <el-input |
| | | v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸çµè¯ï¼" prop="companyPhone"> |
| | | <el-input |
| | | v-model="form.companyPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="弿·è¡ï¼" prop="bankAccountName"> |
| | | <el-input |
| | | v-model="form.bankAccountName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´¦å·ï¼" prop="bankAccountNum"> |
| | | <el-input |
| | | v-model="form.bankAccountNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è系人ï¼" prop="contactUserName"> |
| | | <el-input |
| | | v-model="form.contactUserName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»çµè¯ï¼" prop="contactUserPhone"> |
| | | <el-input |
| | | v-model="form.contactUserPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤äººï¼" prop="maintainUserId"> |
| | | <el-select |
| | | v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" prop="maintainTime"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- æ¿è¿å导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body |
| | | > |
| | | <el-upload |
| | | ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <!-- <el-link |
| | | type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate" |
| | | >ä¸è½½æ¨¡æ¿</el-link |
| | | > --> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "æ¿è¿ååç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "èç³»æ¹å¼", |
| | | prop: "companyPhone", |
| | | width:150 |
| | | }, |
| | | { |
| | | label: "弿·è¡", |
| | | prop: "bankAccountName", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è´¦å·", |
| | | prop: "bankAccountNum", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è系人", |
| | | prop: "contactUserName", |
| | | }, |
| | | { |
| | | label: "èç³»çµè¯", |
| | | prop: "contactUserPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width:100 |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openForm("edit", row); |
| | | }, |
| | | disabled: (row) => { |
| | | return row.maintainUserName !== userStore.nickName |
| | | } |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | companyPhone: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserPhone: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | console.log(upload.url + '?updateSupport=' + upload.updateSupport) |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼æ¿è¿å导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼æ¿è¿å导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "æ¿è¿å导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.open = false; |
| | | upload.isUploading = false; |
| | | proxy.$refs["uploadRef"].handleRemove(file); |
| | | getList(); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then((res) => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/system/supplier/export", {}, "æ¿è¿åæ¡£æ¡.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter(item => item.maintainUserName !== userStore.nickName); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delSupplier(ids) |
| | | .then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |