Commit 2d4870d1 by qinjianhui

Merge branch 'dev' into 'master'

Dev

See merge request !101
parents 02099e7c a82400be
......@@ -23,6 +23,14 @@ export function updateRuleByIdApi(data: PostData) {
)
}
// 规则开关
export function ruleSwitchApi(data: { id: number; status: string }) {
return axios.post<never, BasePaginationData<never>>(
'factory/podJomallOrderUsArrangeRule/ruleSwitch',
data,
)
}
// us规则列表
export function getByFactoryNoApi(data: { factoryNo: number }) {
return axios.get<never, BaseRespData<never>>(
......
......@@ -10,6 +10,9 @@ import {
AnyObject,
InterProductList,
ExportInWarehouseInfo,
stockingPlanSearchForm,
InterStackingPlanDetail,
InterWarehouseBase
} from '@/types/api/warehouse'
export interface LogListData {
createTime: string
......@@ -596,3 +599,121 @@ export function deleteWarehouseOutRecordApi(ids: string) {
},
)
}
// 备货计划 树状图
export function getStackingPlanStatusTree() {
return axios.get<never, BaseRespData<InterWarehouseTree[]>>(
'factoryStockingPlanRecord/status_tree',
)
}
// 备货计划 列表
export function getStackingPlanListPage(data: stockingPlanSearchForm, currentPage: number,
pageSize: number,) {
return axios.post<never, BasePaginationData<InterWarehousePage>>(
'factoryStockingPlanRecord/list_page',
{
...data,
currentPage,
pageSize,
},
)
}
// 备货计划 新增
export function addStackingPlanApi(data: InterWarehouseDetail) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/add',
data,
)
}
// 备货计划 编辑
export function updateStackingPlanApi(data: InterStackingPlanDetail) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/update',
data,
)
}
// 备货计划 详情
export function getStackingPlanDetailApi(id: number | undefined) {
return axios.get<never, BaseRespData<InterStackingPlanDetail>>(
'factoryStockingPlanRecord/get',
{
params: {
id,
},
},
)
}
// 备货计划 日志
export function getStackingPlanLogApi(stockingPlanRecordId?: number) {
return axios.get<never, BaseRespData<LogListData[]>>(
`factoryStockingPlanRecord/log/${stockingPlanRecordId}`,
)
}
// 备货计划 驳回
export function rejectStackingPlanApi({
list,
rejectReason,
status,
}: {
list: WarehouseParams[]
rejectReason: string
status: string
}) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/reject',
{
list,
rejectReason,
status,
},
)
}
// 备货计划 删除
export function deleteStackingPlanApi(ids: string) {
return axios.get<never, BaseRespData<never>>(
'factoryStockingPlanRecord/delete',
{
params: { ids },
},
)
}
// 备货计划 更新物流单号
export function updateShipmentNumberApi(data: InterWarehouseBase[]) {
return axios.post<never, BaseRespData<never>>(
'factoryStockingPlanRecord/update_shipmentNumber',
{ stockingPlanRecordParamList: data },
)
}
// 备货计划 导出
export function stackingPlanRecordExport(data: ExportInWarehouseInfo) {
return axios.post<never, BasePaginationData<never>>(
'factoryStockingPlanRecord/export',
data,
{
responseType: 'blob',
},
)
}
// 备货计划 盘点
export function scanBoxCodeApi(boxCode: string) {
return axios.get<never, BaseRespData<never>>(
'factoryStockingPlanRecord/scan_box_code',
{
params: { boxCode },
},
)
}
// 备货计划 打印箱贴
export function printBarcodeApi(data: { id: number, dataVersion: number }[]) {
return axios.post<never, BaseRespData<never[]>>(
'factoryStockingPlanRecord/print_barcode',
data,
)
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import {
RouteLocationNormalized,
NavigationGuardNext,
} from 'vue-router'
import { cleanupImagePreview } from '@/utils/hooks/useImagePreview.'
import Login from '@/views/Login.vue'
import Reset from '@/views/Reset.vue'
......@@ -31,6 +32,7 @@ import receiptDoc from '@/views/warehouse/receiptDoc.vue'
import issueDoc from '@/views/warehouse/issueDoc.vue'
import ExternalAuthorisationPage from '@/views/system/externalAuthorisationPage.vue'
import CustomersPage from '@/views/system/CustomersPage.vue'
import stockingPlan from '@/views/warehouse/stockingPlan.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
......@@ -129,7 +131,7 @@ const router = createRouter({
meta: {
title: '下载生产客户端',
},
component: () => {},
component: () => { },
beforeEnter() {
// 假设你的下载链接是这个
const downloadLink = '/exeFiles/JomallProductionAssistantSetup.exe'
......@@ -280,6 +282,13 @@ const router = createRouter({
component: issueDoc,
},
{
path: '/warehouse/stocking-plan',
meta: {
title: '备货计划',
},
component: stockingPlan,
},
{
path: '/warehouse/warning',
meta: {
title: '仓库预警',
......@@ -333,6 +342,8 @@ router.beforeEach(
_from: RouteLocationNormalized,
next: NavigationGuardNext,
) => {
// 路由切换时清理图片预览,防止预览元素残留
cleanupImagePreview()
const token = getToken()
if (to.query.factoryCode) {
localStorage.setItem('factory_code', String(to.query.factoryCode))
......
......@@ -88,7 +88,6 @@ const menu: MenuItem[] = [
id: 124,
label: '出库单',
},
{
index: '/warehouse/manage',
id: 121,
......@@ -99,6 +98,11 @@ const menu: MenuItem[] = [
id: 122,
label: '库位管理',
},
{
index: '/warehouse/stocking-plan',
id: 124,
label: '备货计划',
},
],
},
......@@ -216,7 +220,7 @@ const menu: MenuItem[] = [
label: '工厂设置',
},
],
},
},
// {
// index: '',
// id: 3,
......
......@@ -12,6 +12,7 @@ export interface warehouseSearchForm {
warehouseSku?: string
warehouseId?: number | string
id?: number
remark?: string
}
export interface InterProductList {
createTime?: string
......@@ -21,6 +22,7 @@ export interface InterProductList {
productNo?: string | null //custom的货号
buyStored?: number | null //入库数量
outCount?: number | null //出库数量
stockUpStored?: number | null //备货数量
remark?: string | null
skuImage?: string
skuName?: string
......@@ -53,9 +55,10 @@ export interface InterWarehouseBase {
rejectReason?: string | null
number?: number | string | null
supplierItemNo?: string | null
sourceOn?: string | null //备货单号or入库单号
}
// 主表列表ts
export interface InterWarehousePage extends InterWarehouseBase {}
export interface InterWarehousePage extends InterWarehouseBase { }
// 子表列表ts
export interface InterWarehouseDetail extends InterWarehouseBase {
productList: InterProductList[]
......@@ -80,6 +83,7 @@ export interface InterProductList {
productNo?: string | null //货号
buyStored?: number | null //入库数量
outCount?: number | null //出库数量
stockUpStored?: number | null //备货数量
usableInventory?: number | null //可用库存数量
remark?: string | null
skuImage?: string
......@@ -117,3 +121,21 @@ export interface ILocation {
locationId?: number | null
locationCode?: string | null
}
// 备货计划 查询
export interface stockingPlanSearchForm extends InterWarehouseBase {
timeType?: string
startDate?: string
endDate?: string
dateStr?: string
warehouseSku?: string
}
// 备货计划
export interface InterStackingPlanDetail extends InterWarehouseDetail {
boxSum?: number
checkBoxSum?: number
box?: number | string
}
import { ref } from 'vue'
import { ref, onUnmounted } from 'vue'
export default function useImagePreview() {
const show = ref(false)
const div = document.createElement('div')
div.style.position = 'fixed'
div.style.zIndex = '9999999999999'
div.style.display = 'none'
const img = document.createElement('img')
img.style.width = '300px'
div.appendChild(img)
document.body.appendChild(div)
// 单例模式:所有实例共享同一个预览元素
let previewDiv: HTMLDivElement | null = null
let previewImg: HTMLImageElement | null = null
const show = ref(false)
let currentTarget: HTMLElement | null = null
let mousemoveHandler: ((ev: MouseEvent) => void) | null = null
// 初始化预览元素(只创建一次)
function initPreviewElement() {
if (previewDiv) return
let currentTarget: HTMLElement | null = null
previewDiv = document.createElement('div')
previewDiv.style.position = 'fixed'
previewDiv.style.zIndex = '9999999999999'
previewDiv.style.display = 'none'
previewImg = document.createElement('img')
previewImg.style.width = '300px'
previewDiv.appendChild(previewImg)
document.body.appendChild(previewDiv)
}
const mousemoveHandler = (ev: MouseEvent) => {
if (!currentTarget) return
const rect = currentTarget.getBoundingClientRect()
const inOrigin =
ev.clientX >= rect.left &&
ev.clientX <= rect.right &&
ev.clientY >= rect.top &&
ev.clientY <= rect.bottom
// 清理函数:移除事件监听器和重置状态
function cleanup() {
if (mousemoveHandler) {
window.removeEventListener('mousemove', mousemoveHandler)
mousemoveHandler = null
}
if (previewDiv) {
previewDiv.style.display = 'none'
}
show.value = false
currentTarget = null
}
const divRect = div.getBoundingClientRect()
const inPreview =
ev.clientX >= divRect.left &&
ev.clientX <= divRect.right &&
ev.clientY >= divRect.top &&
ev.clientY <= divRect.bottom
// 导出清理函数,供路由切换时使用
export function cleanupImagePreview() {
cleanup()
}
if (!inOrigin && !inPreview) {
div.style.display = 'none'
show.value = false
window.removeEventListener('mousemove', mousemoveHandler)
currentTarget = null
export default function useImagePreview() {
// 确保预览元素已初始化
initPreviewElement()
// 创建 mousemove 处理器(如果还没有)
if (!mousemoveHandler) {
mousemoveHandler = (ev: MouseEvent) => {
if (!currentTarget || !previewDiv) {
cleanup()
return
}
const rect = currentTarget.getBoundingClientRect()
const inOrigin =
ev.clientX >= rect.left &&
ev.clientX <= rect.right &&
ev.clientY >= rect.top &&
ev.clientY <= rect.bottom
const divRect = previewDiv.getBoundingClientRect()
const inPreview =
ev.clientX >= divRect.left &&
ev.clientX <= divRect.right &&
ev.clientY >= divRect.top &&
ev.clientY <= divRect.bottom
if (!inOrigin && !inPreview) {
cleanup()
}
}
}
......@@ -44,12 +77,13 @@ export default function useImagePreview() {
newBorder?: boolean,
positionBOOTTOM?: boolean,
) => {
if (!previewDiv || !previewImg) return
ev.preventDefault()
if (show.value === true) return
img.src = url
img.style.backgroundColor = '#eee'
if (newBorder) img.style.border = '1px solid #eee'
if (newWitdh) img.style.width = newWitdh
previewImg.src = url
previewImg.style.backgroundColor = '#eee'
if (newBorder) previewImg.style.border = '1px solid #eee'
if (newWitdh) previewImg.style.width = newWitdh
const cW = document.body.clientWidth
const cH = document.body.clientHeight
const cX = ev.clientX
......@@ -59,14 +93,15 @@ export default function useImagePreview() {
else y = cY - 150
if (cX + 300 >= cW) x = cX - 300
else x = cX + 60
img.onload = () => {
div.style.left = x + 'px'
div.style.top = y + 'px'
div.style.display = 'block'
previewImg.onload = () => {
if (!previewDiv || !previewImg) return
previewDiv.style.left = x + 'px'
previewDiv.style.top = y + 'px'
previewDiv.style.display = 'block'
if (positionBOOTTOM) {
// 获取图片实际尺寸
const imgWidth = img.clientWidth
const imgHeight = img.clientHeight
const imgWidth = previewImg.clientWidth
const imgHeight = previewImg.clientHeight
// 计算新位置(鼠标正下方)
let x = cX / 2
......@@ -85,20 +120,26 @@ export default function useImagePreview() {
if (y < 0) {
y = 10
}
div.style.left = x + 'px'
div.style.top = y + 'px'
previewDiv.style.left = x + 'px'
previewDiv.style.top = y + 'px'
}
show.value = true
currentTarget = ev.currentTarget as HTMLElement
window.addEventListener('mousemove', mousemoveHandler)
if (mousemoveHandler) {
window.addEventListener('mousemove', mousemoveHandler)
}
}
}
const mouseleaveImg = () => {
if (show.value === false) return
div.style.display = 'none'
show.value = false
// 在 mouseleave 时也要清理事件监听器
cleanup()
}
// 组件卸载时清理(防止内存泄漏)
onUnmounted(() => {
cleanup()
})
return { mouseoverImg, mouseleaveImg }
}
......@@ -355,6 +355,14 @@ const formConfig = computed<IFormConfig[]>(() => [
type: 'switch',
label: '是否默认',
},
{
prop: 'creditCode',
type: 'input',
label: '社会信用代码',
attrs: {
placeholder: '请输入社会信用代码',
},
},
])
async function getCountryList() {
......
......@@ -17,8 +17,24 @@
<div class="box">批次数量:{{ item.arrangeMax }}</div>
<div class="box">每天{{ getTime(item) }}开始自动排单</div>
</div>
<div class="action">
<div style="display: flex; align-items: center; gap: 2px">
<div>状态:</div>
<el-switch
v-model="item.status"
active-value="ACTIVE"
inactive-value="INACTIVE"
active-text="开"
inactive-text="关"
inline-prompt
class="ml-2"
style="
--el-switch-on-color: #42b983;
--el-switch-off-color: #f56c6c;
"
@change="(val:string) => ruleSwitch(item.id, val)"
/>
</div>
<el-icon
size="24"
title="编辑"
......@@ -180,6 +196,22 @@
"
/>
</div>
<div style="display: flex; align-items: center">
<div style="color: #606266; margin-right: 10px">状态:</div>
<el-switch
v-model="editForm.status"
active-value="ACTIVE"
inactive-value="INACTIVE"
active-text="开"
inactive-text="关"
inline-prompt
class="ml-2"
style="
--el-switch-on-color: #42b983;
--el-switch-off-color: #f56c6c;
"
/>
</div>
<div v-if="editForm.isAuto">
<div label="排版类型:">
<el-radio-group v-model="editForm.type">
......@@ -215,6 +247,7 @@ import {
usArrangeRuleApi,
getByFactoryNoApi,
updateRuleByIdApi,
ruleSwitchApi,
} from '@/api/podUsSchedulingRules.ts'
import { Plus, Minus } from '@element-plus/icons-vue'
......@@ -223,7 +256,7 @@ import CustomizeForm from '@/components/CustomizeForm.tsx'
import { Edit } from '@element-plus/icons-vue'
import { debounce } from 'lodash-es'
const editForm = ref<BaseForm>({ isAuto: false })
const editForm = ref<BaseForm>({ isAuto: false, status: 'ACTIVE' })
const tableData = ref([])
import userUserStore from '@/store/user'
const userStore = userUserStore()
......@@ -311,6 +344,7 @@ interface BaseForm {
hour?: string | number
minute?: string | number
second?: string | number
status?: string
}
type ParamKey = `param${number}`
type ParamValue = string | number | boolean | null | undefined
......@@ -433,6 +467,26 @@ const changeSwitch = () => {
editForm.value.templateWidth = undefined
}
const ruleSwitch = async (id: number | undefined, status: string) => {
if (!id) {
return
}
try {
const res = await ruleSwitchApi({
id,
status,
})
ElMessage({
message: res.message,
type: 'success',
offset: window.innerHeight / 2,
})
getList()
} catch (e) {
console.error(e)
}
}
const padTimeUnit = (value: string | number): string => {
const num = Number(value)
// 若转换后是 NaN(无效值),或原始值不存在(null/undefined/''),均返回 '00'
......@@ -513,6 +567,9 @@ const getTime = (item: BaseForm) => {
}
.action {
display: flex;
align-items: center;
gap: 100px;
.iconView {
}
}
......
......@@ -87,6 +87,14 @@
style="width: 160px"
/>
</ElFormItem>
<ElFormItem style="margin-right: 10px" label="备注">
<ElInput
v-model.trim="searchForm.remark"
clearable
placeholder="请输入备注"
style="width: 160px"
/>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search" ref="searchBtnRef"
>查询</ElButton
......@@ -244,6 +252,20 @@
align="center"
></ElTableColumn>
<ElTableColumn
label="创建时间"
show-overflow-tooltip
prop="createTime"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="审核时间"
show-overflow-tooltip
prop="auditTime"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="备注"
show-overflow-tooltip
prop="remark"
......
......@@ -184,6 +184,14 @@
align="center"
></ElTableColumn>
<ElTableColumn
label="备货单号"
show-overflow-tooltip
prop="sourceOn"
width="130"
header-align="center"
align="center"
></ElTableColumn>
<ElTableColumn
label="单据状态"
width="130"
prop="billStatusTxt"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment