feat(芯导): 仓储库存管理/协同审批会议提醒/采购付款查询导出/营销回款流水导出/生产设备补字段
- 仓储物流:库存管理改为 4 个 tab(实时库存/变动明细/库存盘点/库存时间设置);入库加登记人、出库加领用数量;库存预警支持生成采购建议/滞销处理提示
- 协同办公:请假管理改名请假审批、新增合同审批;修复会议纪要加载、新增会议提醒
- 采购管理:开票台账支持发票日期/金额查询;回款流水新增导出
- 营销管理:开票台账支持发票日期/客户/金额查询
- 生产管控:生产订单加产品名称/项目名称/排产数量;生产派工加生产要求/完成期限
- 设备管理:设备保养加保养周期/保养内容;检定记录加下次检定日期
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // åºåçç¹-å页 |
| | | export const getStockTakingPage = (params) => { |
| | | return request({ url: "/stockTaking/listPage", method: "get", params }); |
| | | }; |
| | | // åºåçç¹-æ°å¢ |
| | | export const addStockTaking = (data) => { |
| | | return request({ url: "/stockTaking", method: "post", data }); |
| | | }; |
| | | // åºåçç¹-ä¿®æ¹ |
| | | export const updateStockTaking = (data) => { |
| | | return request({ url: "/stockTaking", method: "put", data }); |
| | | }; |
| | | // åºåçç¹-å é¤ |
| | | export const delStockTaking = (ids) => { |
| | | return request({ url: "/stockTaking/" + ids.join(","), method: "delete" }); |
| | | }; |
| | | |
| | | // åºåæ¶é´è®¾ç½®-å表 |
| | | export const getStockTimeSettingList = () => { |
| | | return request({ url: "/stockTimeSetting/list", method: "get" }); |
| | | }; |
| | | // åºåæ¶é´è®¾ç½®-æ°å¢ |
| | | export const addStockTimeSetting = (data) => { |
| | | return request({ url: "/stockTimeSetting", method: "post", data }); |
| | | }; |
| | | // åºåæ¶é´è®¾ç½®-ä¿®æ¹ |
| | | export const updateStockTimeSetting = (data) => { |
| | | return request({ url: "/stockTimeSetting", method: "put", data }); |
| | | }; |
| | | // åºåæ¶é´è®¾ç½®-å é¤ |
| | | export const delStockTimeSetting = (ids) => { |
| | | return request({ url: "/stockTimeSetting/" + ids.join(","), method: "delete" }); |
| | | }; |
| | |
| | | params, |
| | | }); |
| | | }; |
| | | // çæéè´å»ºè®® / æ»éå¤çæç¤º |
| | | export const generateSuggestion = (data) => { |
| | | return request({ |
| | | url: "/customStorageWarning/generateSuggestion", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | }; |
| | |
| | | <!-- æ ç¾é¡µåæ¢ä¸åç审æ¹ç±»å --> |
| | | <el-tabs v-if="!fixedApproveType" v-model="activeTab" @tab-change="handleTabChange" class="approval-tabs"> |
| | | <el-tab-pane label="èªç±åå审æ¹" name="1"></el-tab-pane> |
| | | <el-tab-pane label="请å管ç" name="2"></el-tab-pane> |
| | | <el-tab-pane label="请å审æ¹" name="2"></el-tab-pane> |
| | | <el-tab-pane label="éå®å®¡æ¹" name="3"></el-tab-pane> |
| | | <el-tab-pane label="æ¥é审æ¹" name="4"></el-tab-pane> |
| | | <el-tab-pane label="éè´å®¡æ¹" name="5"></el-tab-pane> |
| | | <el-tab-pane label="æ¥ä»·å®¡æ¹" name="6"></el-tab-pane> |
| | | <el-tab-pane label="åºåºå®¡æ¹" name="7"></el-tab-pane> |
| | | <el-tab-pane label="åå审æ¹" name="8"></el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | <div class="search_form"> |
| | |
| | | const nameMap = { |
| | | 0: "èªç±åå审æ¹è¡¨", |
| | | 1: "èªç±åå审æ¹è¡¨", |
| | | 2: "请å管ç审æ¹è¡¨", |
| | | 2: "请å审æ¹è¡¨", |
| | | 3: "éå®åå审æ¹è¡¨", |
| | | 4: "æ¥é管ç审æ¹è¡¨", |
| | | 5: "éè´è®¡å审æ¹è¡¨", |
| | | 6: "æ¥ä»·å®¡æ¹è¡¨", |
| | | 7: "åºåºå®¡æ¹è¡¨", |
| | | 8: "åå审æ¹è¡¨", |
| | | } |
| | | const fileName = nameMap[type] || nameMap[0] |
| | | proxy.download(url, {}, `${fileName}.xlsx`) |
| | |
| | | meetings.value = resp2.data.map(item => { |
| | | return { |
| | | ...item, |
| | | participants: JSON.parse(item.participants) |
| | | participants: (() => { |
| | | if (Array.isArray(item.participants)) return item.participants |
| | | const s = String(item.participants || '').trim() |
| | | if (!s) return [] |
| | | if (s.startsWith('[')) { try { return JSON.parse(s) } catch (e) { return [] } } |
| | | return s.split(',').map(v => v.trim()).filter(Boolean) |
| | | })() |
| | | } |
| | | }) |
| | | console.log('ä¼è®®çæ¿é¡µé¢å è½½å®æ') |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- ç«å
æé横å¹
ï¼å³å°å¼å§çä¼è®® --> |
| | | <el-alert |
| | | v-if="upcomingMeetings.length" |
| | | class="remind-banner" |
| | | type="warning" |
| | | :closable="false" |
| | | show-icon |
| | | > |
| | | <template #title> |
| | | ä¼è®®æéï¼{{ upcomingText }} |
| | | </template> |
| | | </el-alert> |
| | | |
| | | <div class="tabs-wrapper"> |
| | | <el-tabs |
| | | v-model="activeTab" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from 'vue' |
| | | import { ref, computed, onMounted, onUnmounted } from 'vue' |
| | | import { ElNotification } from 'element-plus' |
| | | import dayjs from 'dayjs' |
| | | import { getMeetingPublish } from '@/api/collaborativeApproval/meeting.js' |
| | | import MeetSetting from '../notificationManagement/meetSetting/index.vue' |
| | | import MeetIndex from '../notificationManagement/meetIndex/index.vue' |
| | | import MeetApplication from '../notificationManagement/meetApplication/index.vue' |
| | |
| | | function handleTabChange(name) { |
| | | activeTab.value = name |
| | | } |
| | | |
| | | /* ==================== ä¼è®®æéï¼ç«å
+ æµè§å¨/ææºç«¯å¼¹çªï¼ ==================== */ |
| | | const REMIND_WINDOW_MIN = 30 // ä¼è®®å¼å§å 30 åéå
æé |
| | | const REMIND_STORAGE_KEY = 'meeting_remind_sent' |
| | | const POLL_INTERVAL = 60 * 1000 // æ¯ 60 ç§æ£æ¥ä¸æ¬¡ |
| | | |
| | | const upcomingMeetings = ref([]) |
| | | let remindTimer = null |
| | | |
| | | const getSentMap = () => { |
| | | try { |
| | | return JSON.parse(localStorage.getItem(REMIND_STORAGE_KEY) || '{}') |
| | | } catch (e) { |
| | | return {} |
| | | } |
| | | } |
| | | const markSent = (key) => { |
| | | const m = getSentMap() |
| | | m[key] = Date.now() |
| | | // åªä¿çæè¿ 200 æ¡ï¼é¿å
localStorage æ éå¢é¿ |
| | | const entries = Object.entries(m).sort((a, b) => b[1] - a[1]).slice(0, 200) |
| | | localStorage.setItem(REMIND_STORAGE_KEY, JSON.stringify(Object.fromEntries(entries))) |
| | | } |
| | | |
| | | // 计ç®ä¼è®®å¼å§æ¶é´ï¼å
¼å®¹ startTime 为 datetime / 纯æ¶é´ä¸¤ç§æ ¼å¼ï¼ |
| | | const parseStart = (m) => { |
| | | const raw = m.startTime |
| | | if (!raw) return null |
| | | const s = String(raw) |
| | | if (s.length > 10) return dayjs(s) |
| | | if (!m.meetingDate) return null |
| | | return dayjs(`${m.meetingDate} ${s}`) |
| | | } |
| | | |
| | | const checkRemind = async () => { |
| | | try { |
| | | const resp = await getMeetingPublish({ current: 1, size: 100 }) |
| | | const records = (resp && resp.data && resp.data.records) || [] |
| | | const now = dayjs() |
| | | const sent = getSentMap() |
| | | const upcoming = [] |
| | | |
| | | records.forEach((m) => { |
| | | const start = parseStart(m) |
| | | if (!start || !start.isValid()) return |
| | | const diffMin = start.diff(now, 'minute', true) |
| | | // åªæéãå³å°å¼å§ãï¼0 ~ 30 åé |
| | | if (diffMin < 0 || diffMin > REMIND_WINDOW_MIN) return |
| | | const flagKey = `${m.id}_${start.format('YYYYMMDDHHmm')}` |
| | | upcoming.push({ title: m.title || 'ä¼è®®', start, diffMin }) |
| | | |
| | | if (sent[flagKey]) return |
| | | markSent(flagKey) |
| | | ElNotification({ |
| | | title: 'ä¼è®®æé', |
| | | message: `ã${m.title || 'ä¼è®®'}ãå°äº ${start.format('HH:mm')} å¼å§${ |
| | | diffMin <= 1 ? 'ï¼å³å°å¼å§ï¼' : `ï¼çº¦ ${Math.round(diffMin)} åéåï¼` |
| | | }`, |
| | | type: 'warning', |
| | | duration: 15000, |
| | | position: 'bottom-right' |
| | | }) |
| | | }) |
| | | |
| | | upcoming.sort((a, b) => a.start.valueOf() - b.start.valueOf()) |
| | | upcomingMeetings.value = upcoming |
| | | } catch (e) { |
| | | // æé失败ä¸å½±å主æµç¨ |
| | | } |
| | | } |
| | | |
| | | const upcomingText = computed(() => |
| | | upcomingMeetings.value |
| | | .map((x) => `${x.title}ï¼${x.start.format('MM-DD HH:mm')}ï¼`) |
| | | .join('ï¼') |
| | | ) |
| | | |
| | | onMounted(() => { |
| | | checkRemind() |
| | | remindTimer = setInterval(checkRemind, POLL_INTERVAL) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | if (remindTimer) { |
| | | clearInterval(remindTimer) |
| | | remindTimer = null |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .remind-banner { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .tabs-wrapper { |
| | | margin-bottom: 10px; |
| | |
| | | min-height: 400px; |
| | | } |
| | | </style> |
| | | |
| | |
| | | loading.value = true |
| | | let resp = await getExamineList({...searchForm, ...queryParams}) |
| | | approvalList.value = resp.data.records.map(it => { |
| | | let room = roomEnum.value.find(room => it.roomId === room.id) |
| | | it.location = `${room.name}(${room.location})` |
| | | let staffs = JSON.parse(it.participants) |
| | | it.staffCount = staffs.size |
| | | const room = (roomEnum.value || []).find(r => r.id === it.roomId) |
| | | it.location = room ? `${room.name}(${room.location})` : (it.location || '-') |
| | | let staffs = []; if (Array.isArray(it.participants)) { staffs = it.participants } else if (it.participants) { const ps = String(it.participants).trim(); if (ps.startsWith('[')) { try { staffs = JSON.parse(ps) } catch (e) { staffs = [] } } else { staffs = ps.split(',').map(v => v.trim()).filter(Boolean) } }; if (!Array.isArray(staffs)) staffs = []; staffs = staffs.map(v => String(v)); |
| | | it.staffCount = staffs.length |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}` |
| | | it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => { |
| | | it.participants = (staffList.value || []).filter(staff => staffs.some(id => String(id) === String(staff.id))).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})` |
| | |
| | | loading.value = true |
| | | let resp = await getMeetingPublish({...searchForm, ...queryParams}) |
| | | approvalList.value = resp.data.records.map(it => { |
| | | let room = roomEnum.value.find(room => it.roomId === room.id) |
| | | it.location = `${room.name}(${room.location})` |
| | | let staffs = JSON.parse(it.participants) |
| | | it.staffCount = staffs.size |
| | | const room = (roomEnum.value || []).find(r => r.id === it.roomId) |
| | | it.location = room ? `${room.name}(${room.location})` : (it.location || '-') |
| | | let staffs = []; if (Array.isArray(it.participants)) { staffs = it.participants } else if (it.participants) { const ps = String(it.participants).trim(); if (ps.startsWith('[')) { try { staffs = JSON.parse(ps) } catch (e) { staffs = [] } } else { staffs = ps.split(',').map(v => v.trim()).filter(Boolean) } }; if (!Array.isArray(staffs)) staffs = []; staffs = staffs.map(v => String(v)); |
| | | it.staffCount = staffs.length |
| | | it.status = it.publishStatus |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}` |
| | | it.participants = staffList.value.filter(staff => staffs.some(id=>id === staff.id)).map(staff => { |
| | | it.participants = (staffList.value || []).filter(staff => staffs.some(id => String(id) === String(staff.id))).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})` |
| | |
| | | // æ¥è¯¢æ°æ® |
| | | const getList = async () => { |
| | | loading.value = true |
| | | let resp = await getMeetingPublish({ ...searchForm, ...queryParams }) |
| | | meetingList.value = resp.data.records.map(it => { |
| | | let room = roomEnum.value.find(room => it.roomId === room.id) |
| | | it.location = `${room.name}(${room.location})` |
| | | let staffs = JSON.parse(it.participants) |
| | | it.staffCount = staffs.size |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format('HH:mm:ss')} ~ ${dayjs(it.endTime).format('HH:mm:ss')}` |
| | | it.participants = staffList.value.filter(staff => staffs.some(id => id === staff.id)).map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})` |
| | | try { |
| | | const resp = await getMeetingPublish({ ...searchForm, ...queryParams }) |
| | | const records = resp && resp.data && resp.data.records ? resp.data.records : [] |
| | | meetingList.value = records.map(it => { |
| | | const room = (roomEnum.value || []).find(r => r.id === it.roomId) |
| | | it.location = room ? `${room.name}(${room.location})` : (it.location || 'â') |
| | | let staffIds = [] |
| | | const rawParticipants = it.participants |
| | | if (Array.isArray(rawParticipants)) { |
| | | staffIds = rawParticipants |
| | | } else if (rawParticipants) { |
| | | const s = String(rawParticipants).trim() |
| | | if (s.startsWith('[')) { |
| | | try { |
| | | staffIds = JSON.parse(s) |
| | | } catch (e) { |
| | | staffIds = [] |
| | | } |
| | | } else { |
| | | // å
¼å®¹ "130,131,132" éå·åéæ ¼å¼ |
| | | staffIds = s.split(',').map(v => v.trim()).filter(Boolean) |
| | | } |
| | | } |
| | | if (!Array.isArray(staffIds)) staffIds = [] |
| | | staffIds = staffIds.map(v => String(v)) |
| | | it.staffCount = staffIds.length |
| | | const s = it.startTime ? dayjs(it.startTime).format('HH:mm:ss') : '' |
| | | const e2 = it.endTime ? dayjs(it.endTime).format('HH:mm:ss') : '' |
| | | it.meetingTime = `${it.meetingDate || ''} ${s} ~ ${e2}`.trim() |
| | | it.participants = (staffList.value || []) |
| | | .filter(staff => staffIds.some(id => String(id) === String(staff.id))) |
| | | .map(staff => ({ id: staff.id, name: `${staff.staffName}(${staff.postJob})` })) |
| | | return it |
| | | }) |
| | | |
| | | return it |
| | | }) |
| | | total.value = resp.data.total |
| | | loading.value = false |
| | | total.value = (resp && resp.data && resp.data.total) || 0 |
| | | } catch (err) { |
| | | console.error('ä¼è®®çºªè¦å表å 载失败', err) |
| | | meetingList.value = [] |
| | | total.value = 0 |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // æç´¢æé®æä½ |
| | |
| | | |
| | | // 页é¢å è½½æ¶è·åæ°æ® |
| | | onMounted(async () => { |
| | | const [resp1, resp2] = await Promise.all([getRoomEnum(), getStaffOnJob()]) |
| | | roomEnum.value = resp1.data |
| | | staffList.value = resp2.data |
| | | |
| | | try { |
| | | const [resp1, resp2] = await Promise.all([ |
| | | getRoomEnum().catch(() => ({ data: [] })), |
| | | getStaffOnJob().catch(() => ({ data: [] })) |
| | | ]) |
| | | roomEnum.value = (resp1 && resp1.data) || [] |
| | | staffList.value = (resp2 && resp2.data) || [] |
| | | } catch (e) { |
| | | roomEnum.value = [] |
| | | staffList.value = [] |
| | | } |
| | | await getList() |
| | | }) |
| | | </script> |
| | |
| | | width: 100, |
| | | }, |
| | | { |
| | | label: "䏿¬¡æ£å®æ¥æ", |
| | | prop: "nextDate", |
| | | width: 130, |
| | | }, |
| | | { |
| | | label: "å½å
¥äºº", |
| | | prop: "userName", |
| | | }, |
| | |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¿å
»å¨æ"> |
| | | <el-input |
| | | v-model="form.maintenanceCycle" |
| | | placeholder="请è¾å
¥ä¿å
»å¨æï¼å¦ï¼æ¯æä¸æ¬¡ / æ¯å£åº¦ / 30天ï¼" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¿å
Ȍ
容"> |
| | | <el-input |
| | | v-model="form.maintenanceContent" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥ä¿å
Ȍ
容" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | maintenancePlanTime: undefined, // 计åä¿å
»æ¥æ |
| | | maintenanceCycle: undefined, // ä¿å
»å¨æ |
| | | maintenanceContent: undefined, // ä¿å
Ȍ
容 |
| | | }); |
| | | |
| | | const setDeviceModel = (id) => { |
| | |
| | | form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | form.maintenanceCycle = data.maintenanceCycle; |
| | | form.maintenanceContent = data.maintenanceContent; |
| | | }; |
| | | |
| | | const loadForm = () => {}; |
| | |
| | | formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"), |
| | | }, |
| | | { |
| | | label: "ä¿å
»å¨æ", |
| | | align: "center", |
| | | prop: "maintenanceCycle", |
| | | }, |
| | | { |
| | | label: "ä¿å
Ȍ
容", |
| | | align: "center", |
| | | prop: "maintenanceContent", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "å½å
¥äºº", |
| | | align: "center", |
| | | prop: "createUserName", |
| | |
| | | <el-table-column label="åä½" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="ç©åç±»å" prop="itemType" show-overflow-tooltip /> |
| | | <el-table-column label="åææ°é" prop="inboundNum" show-overflow-tooltip /> |
| | | <el-table-column label="é¢ç¨æ°é" prop="requisitionNum" show-overflow-tooltip /> |
| | | <el-table-column label="åä»·(å
)" prop="taxInclusiveUnitPrice" width="150"></el-table-column> |
| | | <el-table-column label="æ»ä»·(å
)" prop="taxInclusiveTotalPrice" width="150"></el-table-column> |
| | | <el-table-column label="åæäºº" prop="createBy" show-overflow-tooltip /> |
| | |
| | | <el-form-item :label="cfg.qtyLabel" prop="inboundQuantity"> |
| | | <el-input-number :step="0.01" :min="0" :max="currentRowNum" style="width: 100%" v-model="form.inboundQuantity" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="é¢ç¨æ°éï¼"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.requisitionNum" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | <el-form-item :label="cfg.dateLabel" prop="inboundTime"> |
| | | <el-date-picker style="width: 100%" v-model="form.inboundTime" value-format="YYYY-MM-DD" format="YYYY-MM-DD" |
| | | type="date" placeholder="è¯·éæ©" clearable /> |
| | |
| | | form.value = { |
| | | productrecordId: '', |
| | | inboundQuantity: currentRowNum.value, |
| | | requisitionNum: 0, |
| | | inboundTime: getCurrentDate(), |
| | | nickName: defaultUserId, |
| | | } |
| | |
| | | form.value = { |
| | | productrecordId: '', |
| | | inboundQuantity: currentRowNum.value, |
| | | requisitionNum: 0, |
| | | inboundTime: getCurrentDate(), |
| | | nickName: '', |
| | | } |
| | |
| | | id: currentRow.value.id, // æ¥æºå
¥åºè®°å½ID |
| | | salesLedgerProductId: currentRow.value.salesLedgerProductId || 0, |
| | | quantity: form.value.inboundQuantity, // åºåºæ°é |
| | | requisitionNum: form.value.requisitionNum, // é¢ç¨æ°é |
| | | time: form.value.inboundTime, // åºåºæ¶é´ |
| | | userId: form.value.nickName, // ç»æäºº |
| | | type: cfg.value.type, // åºåºç±»åï¼3åæ / 2éå®åºåº / 5éè´§åºåº |
| | |
| | | <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"> |
| | | <div style="margin-bottom: 10px; display: flex; align-items: center; gap: 12px;"> |
| | | <span>ç»è®°äººï¼</span> |
| | | <el-input v-model="form.registrant" style="width: 220px" placeholder="请è¾å
¥ç»è®°äºº" clearable /> |
| | | </div> |
| | | <div style="margin-bottom: 10px;" v-if="operationType === 'add'"> |
| | | <el-button type="primary" @click="addProductRow">æ°å¢</el-button> |
| | | </div> |
| | |
| | | supplierName: '', // ä¾åºååç§° |
| | | recorderId: userStore.userId, // å½å
¥äººID |
| | | recorderName: userStore.name, // å½å
¥äººå§å |
| | | registrant: userStore.name, // ç»è®°äºº |
| | | entryDate: getCurrentDate(), // å½å
¥æ¥æ |
| | | remark: '', // 夿³¨ |
| | | }, |
| | |
| | | |
| | | const payloadList = productList.value.map(product => ({ |
| | | id: product.id ?? null, |
| | | registrant: form.value.registrant || '', |
| | | inboundNum: Number(product.inboundNum), |
| | | productCategory: product.productCategory, |
| | | specificationModel: product.specificationModel, |
| | |
| | | <el-table-column label="åä»·(å
)" prop="taxInclusiveUnitPrice" width="150" /> |
| | | <el-table-column label="æ»ä»·(å
)" prop="taxInclusiveTotalPrice" width="150" /> |
| | | <el-table-column label="å
¥åºäºº" prop="createBy" width="80" show-overflow-tooltip /> |
| | | <el-table-column label="ç»è®°äºº" prop="registrant" width="90" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="stock-center"> |
| | | <el-tabs v-model="activeTab" class="center-tabs"> |
| | | <el-tab-pane label="宿¶åºå" name="stock" /> |
| | | <el-tab-pane label="åºåå卿ç»" name="movement" /> |
| | | <el-tab-pane label="åºåçç¹" name="taking" /> |
| | | <el-tab-pane label="åºåæ¶é´è®¾ç½®" name="setting" /> |
| | | </el-tabs> |
| | | <div class="center-body"> |
| | | <keep-alive> |
| | | <component :is="currentComponent" /> |
| | | </keep-alive> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from "vue"; |
| | | import StockRealTime from "../stockManagement/index.vue"; |
| | | import StockMovement from "../stockMovement/index.vue"; |
| | | import StockTaking from "../stockTaking/index.vue"; |
| | | import StockTimeSetting from "../stockTimeSetting/index.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "åºå管ç", |
| | | }); |
| | | |
| | | const activeTab = ref("stock"); |
| | | |
| | | const tabMap = { |
| | | stock: StockRealTime, |
| | | movement: StockMovement, |
| | | taking: StockTaking, |
| | | setting: StockTimeSetting, |
| | | }; |
| | | |
| | | const currentComponent = computed(() => tabMap[activeTab.value] || StockRealTime); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .stock-center { |
| | | padding: 10px 12px; |
| | | } |
| | | .center-tabs { |
| | | margin-bottom: 6px; |
| | | } |
| | | /* å页é¢èªå¸¦ç app-container ä¼å¤ä¸å±å
è¾¹è·ï¼è¿é廿 */ |
| | | .center-body :deep(.app-container) { |
| | | padding: 0; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange"> |
| | | <el-tab-pane label="å
¥åºæç»" name="in" /> |
| | | <el-tab-pane label="åºåºæç»" name="out" /> |
| | | </el-tabs> |
| | | |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">产å大类ï¼</span> |
| | | <el-input v-model="searchForm.productCategory" style="width: 220px" placeholder="请è¾å
¥" clearable @change="handleQuery" /> |
| | | <el-button type="primary" style="margin-left: 10px" @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 20em)"> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column v-if="activeTab === 'in'" label="å
¥åºæ¥æ" prop="inboundDate" width="120" /> |
| | | <el-table-column v-else label="åºåºæ¥æ" prop="createTime" width="160" /> |
| | | <el-table-column label="æ¹æ¬¡å·" prop="code" width="140" show-overflow-tooltip /> |
| | | <el-table-column label="产å大类" prop="productCategory" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" width="70" /> |
| | | <el-table-column v-if="activeTab === 'in'" label="å
¥åºæ°é" prop="inboundNum" width="110" /> |
| | | <el-table-column v-else label="åºåºæ°é" prop="inboundNum" width="110" /> |
| | | <el-table-column v-if="activeTab === 'out'" label="é¢ç¨æ°é" prop="requisitionNum" width="110" /> |
| | | <el-table-column label="åä»·(å
)" prop="taxInclusiveUnitPrice" width="120" /> |
| | | <el-table-column label="æ»ä»·(å
)" prop="taxInclusiveTotalPrice" width="130" /> |
| | | <el-table-column label="ç»æäºº" prop="createBy" width="100" show-overflow-tooltip /> |
| | | </el-table> |
| | | <pagination v-show="page.total > 0" :total="page.total" layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" :limit="page.size" @pagination="paginationChange" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { getInPageByCustom } from "@/api/inventoryManagement/stockIn.js"; |
| | | import { getStockOutPage } from "@/api/inventoryManagement/stockOut.js"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | |
| | | const activeTab = ref("in"); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ current: 1, size: 100, total: 0 }); |
| | | const searchForm = reactive({ productCategory: "", timeStr: getCurrentDate() }); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const params = { ...searchForm, ...page }; |
| | | if (activeTab.value === "in") { |
| | | params.flag = false; |
| | | getInPageByCustom(params).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = (res.data && res.data.records) || []; |
| | | page.total = (res.data && res.data.total) || 0; |
| | | }).catch(() => { tableLoading.value = false; }); |
| | | } else { |
| | | getStockOutPage(params).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = (res.data && res.data.records) || []; |
| | | page.total = (res.data && res.data.total) || 0; |
| | | }).catch(() => { tableLoading.value = false; }); |
| | | } |
| | | }; |
| | | const handleQuery = () => { page.current = 1; getList(); }; |
| | | const resetQuery = () => { searchForm.productCategory = ""; handleQuery(); }; |
| | | const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); }; |
| | | const handleTabChange = () => { page.current = 1; getList(); }; |
| | | |
| | | onMounted(() => { getList(); }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .table_list { margin-top: unset; } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">产å大类ï¼</span> |
| | | <el-input v-model="searchForm.productCategory" style="width: 220px" placeholder="请è¾å
¥" clearable @change="handleQuery" /> |
| | | <span class="search_title ml10">è§æ ¼åå·ï¼</span> |
| | | <el-input v-model="searchForm.specificationModel" style="width: 220px" placeholder="请è¾å
¥" clearable @change="handleQuery" /> |
| | | <el-button type="primary" style="margin-left: 10px" @click="handleQuery">æç´¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢çç¹</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="çç¹åå·" prop="code" width="140" show-overflow-tooltip /> |
| | | <el-table-column label="æ¹æ¬¡å·" prop="inboundBatches" width="140" show-overflow-tooltip /> |
| | | <el-table-column label="产å大类" prop="productCategory" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" width="70" /> |
| | | <el-table-column label="è´¦é¢æ°é" prop="bookNum" width="110" /> |
| | | <el-table-column label="å®çæ°é" prop="actualNum" width="110" /> |
| | | <el-table-column label="差弿°é" prop="diffNum" width="110"> |
| | | <template #default="scope"> |
| | | <span :style="{ color: Number(scope.row.diffNum) === 0 ? '' : (Number(scope.row.diffNum) > 0 ? '#67c23a' : '#f56c6c') }"> |
| | | {{ scope.row.diffNum == null ? '-' : scope.row.diffNum }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="çç¹æ¥æ" prop="takingDate" width="120" /> |
| | | <el-table-column label="çç¹äºº" prop="takingUser" width="100" /> |
| | | <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="130" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button link type="danger" size="small" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination v-show="page.total > 0" :total="page.total" layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" :limit="page.size" @pagination="paginationChange" /> |
| | | </div> |
| | | |
| | | <el-dialog v-model="dialogVisible" :title="dialogTitle" width="600px" @close="closeDialog"> |
| | | <el-form :model="form" label-width="110px" label-position="top"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"><el-form-item label="产å大类"><el-input v-model="form.productCategory" clearable /></el-form-item></el-col> |
| | | <el-col :span="12"><el-form-item label="è§æ ¼åå·"><el-input v-model="form.specificationModel" clearable /></el-form-item></el-col> |
| | | <el-col :span="12"><el-form-item label="åä½"><el-input v-model="form.unit" clearable /></el-form-item></el-col> |
| | | <el-col :span="12"><el-form-item label="æ¹æ¬¡å·"><el-input v-model="form.inboundBatches" clearable /></el-form-item></el-col> |
| | | <el-col :span="12"><el-form-item label="è´¦é¢æ°é"><el-input-number v-model="form.bookNum" :step="0.01" :min="0" style="width: 100%" /></el-form-item></el-col> |
| | | <el-col :span="12"><el-form-item label="å®çæ°é"><el-input-number v-model="form.actualNum" :step="0.01" :min="0" style="width: 100%" /></el-form-item></el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="çç¹æ¥æ"> |
| | | <el-date-picker v-model="form.takingDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"><el-form-item label="çç¹äºº"><el-input v-model="form.takingUser" clearable /></el-form-item></el-col> |
| | | <el-col :span="24"><el-form-item label="夿³¨"><el-input v-model="form.remark" type="textarea" :rows="2" /></el-form-item></el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDialog">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { getStockTakingPage, addStockTaking, updateStockTaking, delStockTaking } from "@/api/inventoryManagement/stockTaking.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ current: 1, size: 100, total: 0 }); |
| | | const searchForm = reactive({ productCategory: "", specificationModel: "" }); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref("æ°å¢çç¹"); |
| | | const dialogMode = ref("add"); |
| | | const emptyForm = () => ({ |
| | | id: null, productCategory: "", specificationModel: "", unit: "", inboundBatches: "", |
| | | bookNum: 0, actualNum: 0, takingDate: "", takingUser: userStore.nickName || "", remark: "", |
| | | }); |
| | | const form = reactive(emptyForm()); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockTakingPage({ ...searchForm, ...page }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = (res.data && res.data.records) || []; |
| | | page.total = (res.data && res.data.total) || 0; |
| | | }).catch(() => { tableLoading.value = false; }); |
| | | }; |
| | | const handleQuery = () => { page.current = 1; getList(); }; |
| | | const resetQuery = () => { searchForm.productCategory = ""; searchForm.specificationModel = ""; handleQuery(); }; |
| | | const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); }; |
| | | |
| | | const openForm = (mode, row) => { |
| | | dialogMode.value = mode; |
| | | dialogTitle.value = mode === "add" ? "æ°å¢çç¹" : "ç¼è¾çç¹"; |
| | | Object.assign(form, emptyForm()); |
| | | if (mode === "edit" && row) { |
| | | Object.keys(form).forEach((k) => { if (row[k] !== undefined) form[k] = row[k]; }); |
| | | } |
| | | dialogVisible.value = true; |
| | | }; |
| | | const closeDialog = () => { dialogVisible.value = false; }; |
| | | const submitForm = () => { |
| | | const payload = { ...form }; |
| | | const req = dialogMode.value === "add" ? addStockTaking(payload) : updateStockTaking(payload); |
| | | req.then(() => { |
| | | ElMessage.success(dialogMode.value === "add" ? "æ°å¢æå" : "ä¿®æ¹æå"); |
| | | closeDialog(); |
| | | getList(); |
| | | }).catch(() => ElMessage.error("æä½å¤±è´¥")); |
| | | }; |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm("确认å é¤è¯¥çç¹è®°å½ï¼", "æç¤º", { type: "warning" }).then(() => { |
| | | delStockTaking([row.id]).then(() => { ElMessage.success("å 餿å"); getList(); }); |
| | | }).catch(() => {}); |
| | | }; |
| | | |
| | | onMounted(() => { getList(); }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .table_list { margin-top: unset; } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">åºåæ¶é´è®¾ç½®ï¼é
ç½®åºåé¢è¦æ£æµæ¶é´ãçç¹å¨æãå¨è½¬çé¢è¦å¤©æ°ç</span> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢è®¾ç½®</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" border v-loading="tableLoading" height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="é¢è¦æ£æµæ¶é´" prop="warningCheckTime" width="140" /> |
| | | <el-table-column label="çç¹å¨æ" prop="stockTakingCycle" width="120" /> |
| | | <el-table-column label="å¨è½¬çé¢è¦å¤©æ°" prop="turnoverWarnDays" width="150" /> |
| | | <el-table-column label="æ¯æèªå¨çç¹æ¥" prop="autoTakingDay" width="150" /> |
| | | <el-table-column label="æ¯å¦å¯ç¨" prop="enabled" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.enabled === 1 ? 'success' : 'info'">{{ scope.row.enabled === 1 ? 'å¯ç¨' : 'åç¨' }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="130" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| | | <el-button link type="danger" size="small" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <el-dialog v-model="dialogVisible" :title="dialogTitle" width="560px" @close="closeDialog"> |
| | | <el-form :model="form" label-width="140px" label-position="top"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="é¢è¦æ£æµæ¶é´(HH:mm)"> |
| | | <el-time-picker v-model="form.warningCheckTime" format="HH:mm" value-format="HH:mm" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="çç¹å¨æ"> |
| | | <el-select v-model="form.stockTakingCycle" style="width: 100%" placeholder="è¯·éæ©"> |
| | | <el-option label="æ¯æ¥" value="æ¥" /> |
| | | <el-option label="æ¯å¨" value="å¨" /> |
| | | <el-option label="æ¯æ" value="æ" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¨è½¬çé¢è¦å¤©æ°"> |
| | | <el-input-number v-model="form.turnoverWarnDays" :min="1" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯æèªå¨çç¹æ¥"> |
| | | <el-input-number v-model="form.autoTakingDay" :min="1" :max="31" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦å¯ç¨"> |
| | | <el-switch v-model="form.enabled" :active-value="1" :inactive-value="0" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDialog">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { getStockTimeSettingList, addStockTimeSetting, updateStockTimeSetting, delStockTimeSetting } from "@/api/inventoryManagement/stockTaking.js"; |
| | | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const dialogVisible = ref(false); |
| | | const dialogTitle = ref("æ°å¢è®¾ç½®"); |
| | | const dialogMode = ref("add"); |
| | | const emptyForm = () => ({ |
| | | id: null, warningCheckTime: "09:00", stockTakingCycle: "æ", turnoverWarnDays: 30, autoTakingDay: 1, enabled: 1, remark: "", |
| | | }); |
| | | const form = reactive(emptyForm()); |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockTimeSettingList().then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data || []; |
| | | }).catch(() => { tableLoading.value = false; }); |
| | | }; |
| | | const openForm = (mode, row) => { |
| | | dialogMode.value = mode; |
| | | dialogTitle.value = mode === "add" ? "æ°å¢è®¾ç½®" : "ç¼è¾è®¾ç½®"; |
| | | Object.assign(form, emptyForm()); |
| | | if (mode === "edit" && row) { |
| | | Object.keys(form).forEach((k) => { if (row[k] !== undefined) form[k] = row[k]; }); |
| | | } |
| | | dialogVisible.value = true; |
| | | }; |
| | | const closeDialog = () => { dialogVisible.value = false; }; |
| | | const submitForm = () => { |
| | | const payload = { ...form }; |
| | | const req = dialogMode.value === "add" ? addStockTimeSetting(payload) : updateStockTimeSetting(payload); |
| | | req.then(() => { |
| | | ElMessage.success(dialogMode.value === "add" ? "æ°å¢æå" : "ä¿®æ¹æå"); |
| | | closeDialog(); |
| | | getList(); |
| | | }).catch(() => ElMessage.error("æä½å¤±è´¥")); |
| | | }; |
| | | const handleDelete = (row) => { |
| | | ElMessageBox.confirm("确认å é¤è¯¥è®¾ç½®ï¼", "æç¤º", { type: "warning" }).then(() => { |
| | | delStockTimeSetting([row.id]).then(() => { ElMessage.success("å 餿å"); getList(); }); |
| | | }).catch(() => {}); |
| | | }; |
| | | |
| | | onMounted(() => { getList(); }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .table_list { margin-top: unset; } |
| | | </style> |
| | |
| | | <span v-else>-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="建议类å" prop="suggestionType" width="110" show-overflow-tooltip /> |
| | | <el-table-column label="建议å
容" prop="suggestionContent" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="210" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="handleSuggestion(scope.row, 'éè´å»ºè®®')">éè´å»ºè®®</el-button> |
| | | <el-button link type="warning" size="small" @click="handleSuggestion(scope.row, 'æ»éå¤ç')">æ»éæç¤º</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | |
| | | import { ElMessage } from 'element-plus' |
| | | import pagination from '@/components/PIMTable/Pagination.vue' |
| | | import { |
| | | getStockWarningLedgerPage |
| | | getStockWarningLedgerPage, |
| | | generateSuggestion |
| | | } from '@/api/inventoryManagement/stockWarningLedger.js' |
| | | |
| | | // ååºå¼æ°æ® |
| | |
| | | } |
| | | |
| | | // 页é¢å è½½ |
| | | // çæéè´å»ºè®® / æ»éå¤çæç¤º |
| | | const handleSuggestion = (row, type) => { |
| | | generateSuggestion({ id: row.id, type }).then((res) => { |
| | | ElMessage({ message: res.msg || res.data || 'å·²çæ', type: 'success', duration: 6000, showClose: true }) |
| | | getList() |
| | | }).catch(() => { |
| | | ElMessage.error('çæå¤±è´¥') |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | |
| | | @change="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="åç¥¨æ¥æ"> |
| | | <el-date-picker |
| | | v-model="searchForm.issueDateRange" |
| | | style="width: 250px" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | clearable |
| | | @change="handleIssueDateChange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å票éé¢"> |
| | | <el-input |
| | | v-model="searchForm.invoiceAmountStart" |
| | | style="width: 110px" |
| | | placeholder="æå°" |
| | | clearable |
| | | @change="handleQuery" |
| | | /> |
| | | <span style="margin: 0 6px">-</span> |
| | | <el-input |
| | | v-model="searchForm.invoiceAmountEnd" |
| | | style="width: 110px" |
| | | placeholder="æå¤§" |
| | | clearable |
| | | @change="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-checkbox |
| | | v-model="searchForm.status" |
| | |
| | | width:200 |
| | | }, |
| | | { |
| | | label: "åç¥¨æ¥æ", |
| | | prop: "issueDate", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "å票éé¢(å
)", |
| | | prop: "invoiceAmount", |
| | | formatData: (params) => { |
| | |
| | | searchForm: { |
| | | supplierNameOrContractNo: "", |
| | | status: false, |
| | | issueDateRange: [], |
| | | issueDateStart: undefined, |
| | | issueDateEnd: undefined, |
| | | invoiceAmountStart: undefined, |
| | | invoiceAmountEnd: undefined, |
| | | }, |
| | | form: { |
| | | purchaseContractNumber: "", |
| | |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | // åç¥¨æ¥æåºé´åå |
| | | const handleIssueDateChange = (val) => { |
| | | if (val && val.length === 2) { |
| | | searchForm.issueDateStart = val[0]; |
| | | searchForm.issueDateEnd = val[1]; |
| | | } else { |
| | | searchForm.issueDateStart = undefined; |
| | | searchForm.issueDateEnd = undefined; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | invoiceListPage({ ...searchForm, ...page }).then((res) => { |
| | | const params = { ...searchForm, ...page }; |
| | | // åç¥¨æ¥æåºé´ç¨ start/end ä¼ ç»å端ï¼å»æä»
å端ç¨çæ°ç» |
| | | delete params.issueDateRange; |
| | | if (params.invoiceAmountStart === "" || params.invoiceAmountStart === null) delete params.invoiceAmountStart; |
| | | if (params.invoiceAmountEnd === "" || params.invoiceAmountEnd === null) delete params.invoiceAmountEnd; |
| | | invoiceListPage(params).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.records; |
| | | page.total = res.total; |
| | |
| | | > |
| | | æç´¢ |
| | | </el-button> |
| | | <el-button @click="handleExport">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | // 导åºä»æ¬¾æµæ°´ï¼æå½åæ¥è¯¢æ¡ä»¶å¯¼åºå
¨é¨ï¼ |
| | | const handleExport = () => { |
| | | const { paymentDate, ...rest } = searchForm; |
| | | proxy.download("/purchase/paymentRegistration/export", { ...rest }, "仿¬¾æµæ°´.xlsx"); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | |
| | | prop: "pendingNum", |
| | | width: 100, |
| | | }, |
| | | { |
| | | label: "çäº§è¦æ±", |
| | | prop: "productionRequirement", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "宿æé", |
| | | prop: "completionDeadline", |
| | | width: 120, |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | |
| | | v-model="dialogFormVisible" |
| | | title="ç产派工" |
| | | width="50%" |
| | | top="5vh" |
| | | @close="closeDia" |
| | | > |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="çäº§è¦æ±ï¼" prop="productionRequirement"> |
| | | <el-input |
| | | v-model="form.productionRequirement" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="请è¾å
¥çäº§è¦æ±" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="宿æéï¼" prop="completionDeadline"> |
| | | <el-date-picker |
| | | v-model="form.completionDeadline" |
| | | type="date" |
| | | placeholder="è¯·éæ©å®ææé" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | |
| | | schedulingDate: "", |
| | | pendingQuantity: "", |
| | | salesLedgerProductId: "", |
| | | productionRequirement: "", |
| | | completionDeadline: "", |
| | | }, |
| | | rules: { |
| | | schedulingNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" },], |
| | |
| | | form.value.schedulingNum = 0 |
| | | form.value.schedulingUserId = userStore.id |
| | | form.value.schedulingDate = dayjs().format("YYYY-MM-DD"); |
| | | form.value.productionRequirement = ""; |
| | | form.value.completionDeadline = ""; |
| | | } |
| | | |
| | | // |
| | |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="产ååç§°" prop="productName"> |
| | | <el-input |
| | | v-model="form.productName" |
| | | placeholder="请è¾å
¥äº§ååç§°" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="项ç®åç§°" prop="projectName"> |
| | | <el-input |
| | | v-model="form.projectName" |
| | | placeholder="请è¾å
¥é¡¹ç®åç§°" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="è§æ ¼åå·" prop="specificationModel"> |
| | | <el-input |
| | | v-model="form.specificationModel" |
| | |
| | | prop: "productCategory", |
| | | }, |
| | | { |
| | | label: "产ååç§°", |
| | | prop: "productName", |
| | | }, |
| | | { |
| | | label: "项ç®åç§°", |
| | | prop: "projectName", |
| | | }, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | | prop: "specificationModel", |
| | | }, |
| | |
| | | label: "æ°é", |
| | | prop: "quantity", |
| | | }, |
| | | // { |
| | | // label: "æäº§æ°é", |
| | | // prop: "schedulingNum", |
| | | // width: 100, |
| | | // }, |
| | | { |
| | | label: "æäº§æ°é", |
| | | prop: "schedulingNum", |
| | | width: 100, |
| | | }, |
| | | // { |
| | | // label: "å®å·¥æ°é", |
| | | // prop: "successNum", |
| | |
| | | id: null, |
| | | registerDate: dayjs().format("YYYY-MM-DD"), |
| | | productCategory: "", |
| | | productName: "", |
| | | projectName: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: null, |
| | |
| | | form.id = row.id; |
| | | form.registerDate = row.registerDate; |
| | | form.productCategory = row.productCategory; |
| | | form.productName = row.productName; |
| | | form.projectName = row.projectName; |
| | | form.specificationModel = row.specificationModel; |
| | | form.unit = row.unit; |
| | | form.quantity = row.quantity; |
| | |
| | | form.id = null; |
| | | form.registerDate = dayjs().format("YYYY-MM-DD"); |
| | | form.productCategory = ""; |
| | | form.productName = ""; |
| | | form.projectName = ""; |
| | | form.specificationModel = ""; |
| | | form.unit = ""; |
| | | form.quantity = null; |
| | |
| | | const payload = { |
| | | registerDate: form.registerDate, |
| | | productCategory: form.productCategory, |
| | | productName: form.productName, |
| | | projectName: form.projectName, |
| | | specificationModel: form.specificationModel, |
| | | unit: form.unit, |
| | | quantity: form.quantity, |
| | |
| | | <el-date-picker style="width: 100%" v-model="searchForm.createTimeStart" value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD" type="date" placeholder="è¯·éæ©" clearable @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="å票éé¢"> |
| | | <el-input v-model="searchForm.invoiceAmountStart" style="width: 110px" placeholder="æå°" clearable @change="handleQuery" /> |
| | | <span style="margin: 0 6px">-</span> |
| | | <el-input v-model="searchForm.invoiceAmountEnd" style="width: 110px" placeholder="æå¤§" clearable @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="䏿¾ç¤ºæå票è¡"> |
| | | <el-checkbox v-model="searchForm.status" @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery"> æç´¢ </el-button> |
| | | <el-button @click="resetForm"> éç½® </el-button> |
| | | <el-button @click="handleOut" type="primary">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | |
| | | invoiceDateStart: dayjs().startOf("month").format("YYYY-MM-DD"), |
| | | invoiceDateEnd: dayjs().endOf("month").format("YYYY-MM-DD"), |
| | | createTimeStart: "", // å½å
¥æ¥æ |
| | | invoiceAmountStart: undefined, |
| | | invoiceAmountEnd: undefined, |
| | | }, |
| | | form: { |
| | | salesLedgerId: "", |
| | |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/invoiceLedger/export", {}, "å¼ç¥¨å°è´¦.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼éä»¶ä¸ä¼ å¼¹çª |
| | | const handleDownload = (val) => { |
| | | fileList.value = []; |
| | |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery"> æç´¢ </el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | // 导åºåæ¬¾æµæ°´ï¼æå½åæ¥è¯¢æ¡ä»¶ï¼ |
| | | const handleOut = () => { |
| | | const { receiptPaymentDate, ...rest } = searchForm; |
| | | proxy.download("/receiptPayment/exportOne", { ...rest }, "忬¾æµæ°´.xlsx"); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const { receiptPaymentDate, ...rest } = searchForm; |