Commit c4db0266 by wusiyi Committed by wuqian

feat: 物流分拣规则改造,支持平台+物流公司条件 #1010010

parent f44f8816
...@@ -11,7 +11,11 @@ import { AddDeclarationRuleObj } from '@/views/logistics/types/declarationRule' ...@@ -11,7 +11,11 @@ import { AddDeclarationRuleObj } from '@/views/logistics/types/declarationRule'
import { LogisticsQuotation } from '@/views/logistics/types/logisticsQuotation' import { LogisticsQuotation } from '@/views/logistics/types/logisticsQuotation'
import { LogisticsPartitionObj } from '@/views/logistics/types/logisticsPartition' import { LogisticsPartitionObj } from '@/views/logistics/types/logisticsPartition'
import { ShippingAddressObj } from '@/views/logistics/types/shippingAddress' import { ShippingAddressObj } from '@/views/logistics/types/shippingAddress'
import { IsortingInfo } from '@/types/api/logistics' import {
IsortingInfo,
SortingPortAreaItem,
SortingPortOptionItem,
} from '@/types/api/logistics'
export interface ILogisticsList { export interface ILogisticsList {
code: string code: string
basicsName: string basicsName: string
...@@ -168,9 +172,12 @@ export function getLogisticsWayListByCompanyId(companyId: number) { ...@@ -168,9 +172,12 @@ export function getLogisticsWayListByCompanyId(companyId: number) {
} }
// 获取tictok物流承运商 // 获取tictok物流承运商
export function getTiktokCarrier() { export function getTiktokCarrier() {
return axios.get<never, BaseRespData<{ name: string; id: string, typeCode: string, label: string }[]>>( return axios.get<
'logisticsWay/getTiktokShippingProvider', never,
) BaseRespData<
{ name: string; id: string; typeCode: string; label: string }[]
>
>('logisticsWay/getTiktokShippingProvider')
} }
/** /**
...@@ -461,16 +468,14 @@ export function logisticsCompanyAllCodelist() { ...@@ -461,16 +468,14 @@ export function logisticsCompanyAllCodelist() {
'/logisticsCompany/allCodelist', '/logisticsCompany/allCodelist',
) )
} }
/** // 物流 分拣配置
分拣配置
*/
export function getsortingConfigListApi( export function getsortingConfigListApi(
data: IsortingInfo, data: IsortingInfo,
currentPage: number, currentPage: number,
pageSize: number, pageSize: number,
) { ) {
return axios.post<never, BasePaginationData<IsortingInfo>>( return axios.post<never, BasePaginationData<IsortingInfo>>(
'logistics/sortingConfig/list_page', 'logistics-sort-port-config/list_page',
{ {
...data, ...data,
currentPage, currentPage,
...@@ -481,34 +486,52 @@ export function getsortingConfigListApi( ...@@ -481,34 +486,52 @@ export function getsortingConfigListApi(
// 详情 // 详情
export function getSortingConfig(params: { id: number | string }) { export function getSortingConfig(params: { id: number | string }) {
return axios.get<never, BaseRespData<IsortingInfo>>( return axios.get<never, BaseRespData<IsortingInfo>>(
'logistics/sortingConfig/get', 'logistics-sort-port-config/get',
{ params }, { params },
) )
} }
export function createSortingApi(data: IsortingInfo) { export function createSortingApi(data: IsortingInfo) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'logistics/sortingConfig/add', 'logistics-sort-port-config/add',
data, data,
) )
} }
export function updateSortingApi(data: IsortingInfo) { export function updateSortingApi(data: IsortingInfo) {
return axios.post<never, BaseRespData<never>>( return axios.post<never, BaseRespData<never>>(
'logistics/sortingConfig/update', 'logistics-sort-port-config/update',
data, data,
) )
} }
export function deleteSortingApi(params: { export function deleteSortingApi(params: { id: number }) {
ids: string
type: string | number
}) {
return axios.get<never, BaseRespData<never>>( return axios.get<never, BaseRespData<never>>(
'logistics/sortingConfig/delete', 'logistics-sort-port-config/delete',
{ {
params, params,
}, },
) )
} }
// 分拣配置 查询可用分拣口
export function getSortingPortAreaListApi() {
return axios.get<never, BaseRespData<SortingPortAreaItem[]>>(
'logistics-sort-port-config/area-list',
)
}
// 分拣口规则 条件类型
export function getSortPortConditionTypeListApi() {
return axios.get<never, BaseRespData<SortingPortOptionItem[]>>(
'logistics-sort-port-config/condition-type',
)
}
// 分拣口规则 操作符
export function getSortPortOperatorListApi() {
return axios.get<never, BaseRespData<SortingPortOptionItem[]>>(
'logistics-sort-port-config/operator-list',
)
}
// 物流跟踪 获取菜单树 // 物流跟踪 获取菜单树
export function logisticStatusList() { export function logisticStatusList() {
return axios.get<never, BaseRespData<LogisticsTrackingTree[]>>( return axios.get<never, BaseRespData<LogisticsTrackingTree[]>>(
......
...@@ -15,11 +15,34 @@ export interface Ilogistics { ...@@ -15,11 +15,34 @@ export interface Ilogistics {
createTime?: string createTime?: string
updateTime?: string | null updateTime?: string | null
} }
export interface SortingPortCondition {
id?: number
ruleId?: number
conditionType: string
operator: string
conditionValue?: string | number | string[]
}
export interface IsortingInfo { export interface IsortingInfo {
id?: number id?: number
sortingFacility?: string | null sortingRemark?: string
sortingArea: number | null sortingArea?: number | null
sortingAreaName?: string | null sortingAreaName?: string | null
serviceCode: string | null matchType?: 1 | 2
type?: string | number sortNo?: number
conditions?: SortingPortCondition[]
conditionsText?: string
}
export interface SortingPortAreaItem {
code: number
desc: string
used: boolean
}
export interface SortingPortOptionItem {
desc: string
code: string
used?: boolean
} }
<template>
<ElDialog
v-model="visible"
:title="isEdit ? '编辑分拣口' : '新增分拣口'"
:close-on-click-modal="false"
width="800px"
>
<el-form ref="formRef" label-width="120px" :model="form" :rules="rules">
<el-form-item label="分拣口说明" prop="sortingRemark">
<el-input
v-model="form.sortingRemark"
style="width: 100%"
clearable
maxlength="100"
show-word-limit
placeholder="请输入分拣口说明"
/>
</el-form-item>
<el-form-item label="分拣口" prop="sortingArea">
<el-select
v-model="form.sortingArea"
style="width: 200px"
placeholder="请选择"
>
<el-option
v-for="item in areaList"
:key="item.code"
:label="item.desc"
:value="item.code"
/>
</el-select>
</el-form-item>
<el-form-item label="分拣口规则" prop="conditions">
<div class="sorting-rules">
<div class="header">
<span class="mr-10">满足条件</span>
<el-radio-group v-model="form.matchType">
<el-radio :value="1">满足以下所有条件</el-radio>
<el-radio :value="2">满足以下任一条件</el-radio>
</el-radio-group>
</div>
<div
v-for="(item, index) in form.conditions"
:key="index"
class="content"
>
<el-select
v-model="item.conditionType"
style="width: 160px"
placeholder="请选择分拣口规则"
@change="handleConditionTypeChange(item)"
>
<el-option
v-for="rule in getAvailableConditionTypes(index)"
:key="rule.code"
:label="rule.desc"
:value="rule.code"
/>
</el-select>
<el-select
v-model="item.operator"
style="width: 160px"
placeholder="请选择关系"
>
<el-option
v-for="operator in operatorList"
:key="operator.code"
:label="operator.desc"
:value="operator.code"
/>
</el-select>
<template v-if="item.conditionType === 'order_platform'">
<el-select
v-model="item.conditionValue"
class="platform-select"
style="width: 160px"
placeholder="请选择平台"
filterable
multiple
collapse-tags
collapse-tags-tooltip
:max-collapse-tags="1"
clearable
popper-class="customize-select-style"
>
<el-option
v-for="platform in platformList"
:key="platform.type"
:label="platform.type"
:value="platform.type"
style="width: 160px"
>
<img
:src="`/images/icon/${platform.icon.split('/').pop()}`"
style="height: 20px; margin: 5px 10px 0 0"
/>
<span :title="platform.type">{{ platform.type }}</span>
</el-option>
</el-select>
</template>
<template v-else>
<el-select
v-model="item.conditionValue"
style="width: 160px"
placeholder="请选择物流公司"
filterable
multiple
collapse-tags
collapse-tags-tooltip
:max-collapse-tags="1"
clearable
>
<el-option
v-for="logistics in logisticsMethodsList"
:key="logistics.code"
:label="logistics.basicsName"
:value="logistics.code"
/>
</el-select>
</template>
<el-button
v-if="
(form.conditions?.length ?? 0) <
(conditionTypeList?.length ?? 0)
"
type="primary"
class="rule-action-btn"
:icon="Plus"
size="small"
circle
@click="addConditionItem"
/>
<el-button
v-if="(form.conditions?.length ?? 0) > 1"
color="#F56C6C"
class="rule-action-btn"
:icon="Minus"
size="small"
circle
plain
@click="removeConditionItem(index)"
/>
</div>
</div>
</el-form-item>
<el-form-item label="序号" prop="sortNo">
<el-input-number
v-model="form.sortNo"
:min="1"
:max="999"
style="width: 200px"
step-strictly
controls-position="right"
placeholder="请输入序号"
/>
</el-form-item>
<el-form-item>
<span class="item-info">分拣配置逻辑冲突时,优先执行更小的序号</span>
</el-form-item>
</el-form>
<template #footer>
<div class="flex flex-center">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { Plus, Minus } from '@element-plus/icons-vue'
import type { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import platformJson from '@/json/platform.json'
import type {
Ilogistics,
IsortingInfo,
SortingPortAreaItem,
SortingPortCondition,
SortingPortOptionItem,
} from '@/types/api/logistics'
import {
createSortingApi,
updateSortingApi,
getSortingConfig,
getSortingPortAreaListApi,
getSortPortConditionTypeListApi,
getSortPortOperatorListApi,
} from '@/api/logistics'
const conditionTypeList = ref<SortingPortOptionItem[]>()
const operatorList = ref<SortingPortOptionItem[]>()
defineProps<{
logisticsMethodsList: Ilogistics[]
}>()
const emit = defineEmits<{
success: []
}>()
const visible = ref(false)
const isEdit = ref(false)
const formRef = ref<FormInstance>()
const areaList = ref<SortingPortAreaItem[]>([])
const editId = ref<number>()
const createConditionItem = (): SortingPortCondition => ({
conditionType: '',
operator: '',
conditionValue: undefined,
})
const createDefaultForm = (): IsortingInfo => ({
sortingRemark: '',
sortingArea: null,
sortingAreaName: '',
matchType: 1,
sortNo: 1,
conditions: [createConditionItem()],
})
const form = ref<IsortingInfo>(createDefaultForm())
const getAvailableConditionTypes = (currentIndex: number) => {
const selectedFields = (form.value.conditions ?? [])
.filter((_, index) => index !== currentIndex)
.map((item) => item.conditionType)
return conditionTypeList.value?.filter(
(rule) => !selectedFields.includes(rule.code),
)
}
const handleConditionTypeChange = (item: SortingPortCondition) => {
item.conditionValue = undefined
item.operator = 'in'
}
const validateConditions = (
_rule: unknown,
_value: unknown,
callback: (error?: Error) => void,
) => {
const items = form.value.conditions ?? []
for (let i = 0; i < items.length; i++) {
const item = items[i]
const isValueValid =
Array.isArray(item.conditionValue) && item.conditionValue.length > 0
if (!item.conditionType || !isValueValid || !item.operator) {
callback(new Error('请完善分拣口规则'))
return
}
}
callback()
}
const rules = computed(() => ({
sortingRemark: [
{ required: true, message: '请输入分拣口说明', trigger: 'blur' },
],
sortingArea: [{ required: true, message: '请选择分拣口', trigger: 'change' }],
conditions: [
{ validator: validateConditions, trigger: 'blur' },
{ required: true, message: '请完善分拣口规则', trigger: 'change' },
],
sortNo: [{ required: true, message: '请输入序号', trigger: 'blur' }],
}))
const platformList = platformJson
const formatConditionsForForm = (conditions: SortingPortCondition[]) =>
conditions.map((item) => ({
...item,
conditionValue:
typeof item.conditionValue === 'string'
? item.conditionValue.split(',').filter(Boolean)
: item.conditionValue,
}))
const addConditionItem = () => {
form.value.conditions?.push(createConditionItem())
formRef.value?.validateField('conditions')
}
const removeConditionItem = (index: number) => {
form.value.conditions?.splice(index, 1)
formRef.value?.validateField('conditions')
}
const loadAreaList = async () => {
const res = await getSortingPortAreaListApi()
if (res.code !== 200) return
if (!isEdit.value) {
areaList.value = res.data.filter((item) => item.used === false)
} else {
areaList.value = res.data.filter(
(item) => item.used === false || item.code === form.value.sortingArea,
)
}
}
const loadConditionTypeList = async () => {
const res = await getSortPortConditionTypeListApi()
if (res.code !== 200) return
conditionTypeList.value = res.data
}
const loadOperatorList = async () => {
const res = await getSortPortOperatorListApi()
if (res.code !== 200) return
operatorList.value = res.data
}
const handleSubmit = async () => {
await formRef.value?.validate()
const submitData: IsortingInfo = {
...form.value,
conditions: (form.value.conditions ?? []).map(
(item): SortingPortCondition => ({
...item,
conditionValue: Array.isArray(item.conditionValue)
? item.conditionValue.join(',')
: item.conditionValue,
}),
),
}
const res = isEdit.value
? await updateSortingApi({ ...submitData, id: editId.value })
: await createSortingApi(submitData)
if (res.code !== 200) return
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
visible.value = false
emit('success')
}
const open = async (item?: IsortingInfo) => {
isEdit.value = !!item
editId.value = item?.id
form.value = createDefaultForm()
await Promise.all([loadConditionTypeList(), loadOperatorList()])
if (item?.id) {
const res = await getSortingConfig({ id: item.id })
if (res.code !== 200) return
const conditions = formatConditionsForForm(res.data.conditions ?? [])
form.value = {
...res.data,
conditions: conditions.length ? conditions : [createConditionItem()],
}
}
await loadAreaList()
visible.value = true
formRef.value?.clearValidate()
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.item-info {
font-size: 12px;
color: #666;
line-height: 1;
margin-top: -15px;
}
.sorting-rules {
background-color: #eee;
border-radius: 3px;
padding: 5px 15px;
width: 100%;
.header {
font-size: 12px;
font-weight: 500;
display: flex;
align-items: center;
:deep(.el-radio__label) {
font-size: 12px;
}
}
.content {
display: flex;
align-items: center;
gap: 10px;
margin-top: 8px;
&:first-of-type {
margin-top: 6px;
}
}
.rule-action-btn {
font-size: 16px;
}
.platform-select {
:deep(.el-select__wrapper) {
height: var(--el-component-size);
min-height: var(--el-component-size);
box-sizing: border-box;
}
:deep(.el-select__selection) {
flex-wrap: nowrap;
overflow: hidden;
}
:deep(.el-select__selected-item) {
flex-shrink: 1;
min-width: 0;
overflow: hidden;
}
:deep(.el-tag) {
max-width: 100%;
.el-tag__content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
</style>
<style lang="scss">
.customize-select-style {
.el-select-dropdown__list {
width: 500px;
display: flex;
flex-wrap: wrap;
}
}
</style>
<template>
<div class="user-page flex-column card h-100 overflow-hidden">
<div class="flex-column h-100 overflow-hidden">
<div class="header-filter-form">
<el-form ref="searchFormRef" inline :model="searchForm">
<el-form-item label="分拣口">
<el-select
v-model="searchForm.sortingArea"
clearable
style="width: 160px"
placeholder="请选择分拣口"
>
<el-option
v-for="item in sortingList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="分拣口说明">
<el-input
v-model="searchForm.sortingRemark"
placeholder="请输入分拣口说明"
clearable
style="width: 220px"
/>
</el-form-item>
<el-form-item>
<el-button ref="searchBtnRef" type="primary" @click="search"
>查询</el-button
>
<el-button type="success" @click="createWarehouse">新增</el-button>
</el-form-item>
</el-form>
</div>
<div class="user-content flex-1 flex-column overflow-hidden">
<div class="user-list flex-1 overflow-hidden">
<div v-loading="loading" class="table-container">
<TableView :paginated-data="tableData" :columns="columns">
<template #operation="{ row }">
<el-button type="primary" link @click="updateSorting(row)">
编辑
</el-button>
<el-button type="danger" link @click="handleBatchDelete(row)">
删除
</el-button>
</template>
</TableView>
</div>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</div>
</div>
<CreateSortingRuleDialog
ref="createDialogRef"
:logistics-methods-list="logisticsMethodsList"
@success="search"
/>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { Ilogistics, IsortingInfo } from '@/types/api/logistics' import { Ilogistics, IsortingInfo } from '@/types/api/logistics'
import { import {
Edit,
Delete,
// CirclePlus,
QuestionFilled,
} from '@element-plus/icons-vue'
import platformJson from '@/json/platform.json'
// import useImagePreview from '@/utils/hooks/useImagePreview.'
// const { mouseoverImg, mouseleaveImg } = useImagePreview()
import sortingImg from '@/assets/images/分拣口说明.png'
import {
getsortingConfigListApi, getsortingConfigListApi,
// usableAllList,
createSortingApi,
updateSortingApi,
deleteSortingApi, deleteSortingApi,
getSortingConfig, getSortingPortAreaListApi,
} from '@/api/logistics' } from '@/api/logistics'
import { allErpCodeListApi } from '@/api/podCnOrder' import { allErpCodeListApi } from '@/api/podCnOrder'
import { nextTick, ref } from 'vue' import { ref } from 'vue'
import CreateSortingRuleDialog from './components/CreateSortingRuleDialog.vue'
import { useEnterKeyTrigger } from '@/utils/hooks/useEnterKeyTrigger.ts' import { useEnterKeyTrigger } from '@/utils/hooks/useEnterKeyTrigger.ts'
import TableView from '@/components/TableView.vue'
import type { CustomColumn } from '@/types/table'
import usePageList from '@/utils/hooks/usePageList' import usePageList from '@/utils/hooks/usePageList'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
interface InterForm {
id?: number const columns: CustomColumn<IsortingInfo>[] = [
sortingFacility?: string | null {
sortingArea: number | null key: 'sortNo',
sortingAreaName?: string | null prop: 'sortNo',
serviceCode: string[] label: '序号',
} width: 100,
align: 'center',
},
{
key: 'conditionsText',
prop: 'conditionsText',
label: '分拣口规则',
minWidth: 250,
align: 'left',
},
{
key: 'sortingAreaName',
prop: 'sortingAreaName',
label: '分拣口',
width: 100,
align: 'center',
},
{
key: 'sortingRemark',
prop: 'sortingRemark',
label: '分拣口说明',
minWidth: 200,
align: 'left',
},
{
key: 'operation',
label: '操作',
width: 130,
align: 'center',
slot: 'operation',
},
]
const searchForm = ref({ const searchForm = ref({
sortingFacility: '',
sortingArea: null, sortingArea: null,
serviceCode: [], sortingRemark: '',
})
const selections = ref<IsortingInfo[]>([])
const formRef = ref()
const form = ref<InterForm>({
sortingFacility: '',
sortingArea: null,
sortingAreaName: '',
serviceCode: [],
})
const createData = ref({
title: '',
show: false,
isEdit: false,
form: {
sortingFacility: '',
sortingArea: null,
sortingAreaName: '',
serviceCode: [],
},
})
const activeName = ref('1')
const rules = computed(() => {
return {
sortingFacility: [
{ required: true, message: '请输入分拣设备', trigger: 'blur' },
],
sortingArea: [
{ required: true, message: '请选择分拣口', trigger: 'change' },
],
serviceCode: [
{
required: true,
message: `请选择${activeName.value == '1' ? '物流公司' : '平台'}`,
trigger: 'change',
},
],
}
}) })
const createDialogRef = ref<InstanceType<typeof CreateSortingRuleDialog>>()
const { const {
loading,
currentPage, currentPage,
pageSize, pageSize,
total, total,
...@@ -87,8 +142,6 @@ const { ...@@ -87,8 +142,6 @@ const {
getsortingConfigListApi( getsortingConfigListApi(
{ {
...searchForm.value, ...searchForm.value,
serviceCode: searchForm.value.serviceCode.join(','),
type: activeName.value,
}, },
page, page,
pageSize, pageSize,
...@@ -107,96 +160,21 @@ const getlogisticsMethods = async () => { ...@@ -107,96 +160,21 @@ const getlogisticsMethods = async () => {
] ]
} }
interface interSorting { interface SortingOption {
label: string label: string
value: number value: number
} }
const sortingList = ref<interSorting[]>([ const sortingList = ref<SortingOption[]>([])
{ const getSortingList = async () => {
label: 'L1', const res = await getSortingPortAreaListApi()
value: 1, sortingList.value = (res.data || []).map((item) => ({
}, label: item.desc,
{ value: item.code,
label: 'R1', }))
value: 2,
},
{
label: 'L2',
value: 3,
},
{
label: 'R2',
value: 4,
},
{
label: 'L3',
value: 5,
},
{
label: 'R3',
value: 6,
},
{
label: 'L4',
value: 7,
},
{
label: 'R4',
value: 8,
},
{
label: 'L5',
value: 9,
},
{
label: 'R5',
value: 10,
},
{
label: 'L6',
value: 11,
},
{
label: 'R6',
value: 12,
},
{
label: 'L7',
value: 13,
},
{
label: 'R7',
value: 14,
},
{
label: 'E0',
value: 99,
},
])
const handleSelectionChange = (data: IsortingInfo[]) => {
selections.value = data
}
const handleConfirm = async () => {
await formRef.value?.validate()
if (!createData.value.isEdit) {
await createSortingApi({
...form.value,
serviceCode: form.value.serviceCode.join(','),
type: activeName.value,
})
} else {
await updateSortingApi({
...form.value,
serviceCode: form.value.serviceCode.join(','),
type: activeName.value,
})
}
createData.value.show = false
ElMessage.success('操作成功')
await search()
} }
const handleBatchDelete = async (row: IsortingInfo | null) => { const handleBatchDelete = async (row: IsortingInfo | null) => {
if (!row && !selections.value.length) { if (!row?.id) {
return ElMessage.warning('请选择要删除的数据') return ElMessage.warning('请选择要删除的数据')
} }
await ElMessageBox.confirm('确定要删除吗?', '提示', { await ElMessageBox.confirm('确定要删除吗?', '提示', {
...@@ -204,503 +182,45 @@ const handleBatchDelete = async (row: IsortingInfo | null) => { ...@@ -204,503 +182,45 @@ const handleBatchDelete = async (row: IsortingInfo | null) => {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
}) })
const str = await deleteSortingApi({ id: row.id })
row && row.id
? row.id?.toString()
: selections.value.map((el: IsortingInfo) => el.id).join(',')
await deleteSortingApi({ ids: str, type: activeName.value })
ElMessage.success('删除成功') ElMessage.success('删除成功')
search() search()
} }
// const addLogistics = () => {
// ElMessageBox.prompt('', '物流方式', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// inputErrorMessage: '请输入物流方式',
// inputPlaceholder: '请输入物流方式',
// }).then(({ value }: { value: string }) => {
// if (!value.trim()) {
// ElMessage.error('物流方式不能为空')
// return
// }
// if (form.value.serviceCode.includes(value)) {
// ElMessage.warning('物流方式已存在')
// return
// }
// form.value.serviceCode.push(value)
// ElMessage.success('添加成功')
// })
// }
const createWarehouse = () => { const createWarehouse = () => {
createData.value.show = true createDialogRef.value?.open()
createData.value.isEdit = false
createData.value.title = '新增'
form.value = {
sortingFacility: '',
sortingArea: null,
sortingAreaName: '',
serviceCode: [],
}
nextTick(() => {
formRef.value?.clearValidate()
})
} }
const updateSorting = async (item: IsortingInfo) => { const updateSorting = (item: IsortingInfo) => {
if (!item) return if (!item) return
createData.value.show = true createDialogRef.value?.open(item)
createData.value.isEdit = true
createData.value.title = '修改'
const res = await getSortingConfig({ id: item.id as number | string })
if (res.code !== 200) return
const { serviceCode, ...rest } = res.data
form.value = {
...rest,
serviceCode: serviceCode ? serviceCode.split(',') : [],
}
nextTick(() => {
formRef.value?.clearValidate()
})
}
getlogisticsMethods()
const sortingChange = (v: number) => {
const warehouse = sortingList.value.find((w: interSorting) => w.value == v)
form.value.sortingAreaName = warehouse ? warehouse.label : ''
} }
const handleClick = () => { onMounted(async () => {
const loading = ElLoading.service({ await Promise.all([getSortingList(), getlogisticsMethods()])
fullscreen: true, })
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
try {
searchForm.value = {
sortingFacility: '',
sortingArea: null,
serviceCode: [],
}
search()
} catch (error) {
console.log(error)
} finally {
loading.close()
}
}
const searchFormRef = ref() const searchFormRef = ref()
const searchBtnRef = ref() const searchBtnRef = ref()
useEnterKeyTrigger({ useEnterKeyTrigger({
formRef: searchFormRef, formRef: searchFormRef,
btnRef: searchBtnRef, btnRef: searchBtnRef,
callback: () => {
callback: (event: KeyboardEvent) => {
console.log('回车键被按下', event)
search() search()
}, },
}) })
</script> </script>
<template>
<div class="user-page flex-column card h-100 overflow-hidden">
<el-tabs
v-model="activeName"
type="card"
class="demo-tabs"
@tab-change="handleClick"
>
<el-tab-pane
label="按物流方式分拣(优先级高)"
name="1"
class="flex-column h-100 overflow-hidden"
>
<div class="header-filter-form">
<el-form inline :model="searchForm" ref="searchFormRef">
<el-form-item label="分拣设备">
<el-input
v-model.trim="searchForm.sortingFacility"
placeholder="分拣设备"
clearable
></el-input>
</el-form-item>
<el-form-item label="分拣口">
<el-select
v-model="searchForm.sortingArea"
clearable
style="width: 160px"
>
<el-option
v-for="item in sortingList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="物流公司">
<el-select
v-model="searchForm.serviceCode"
clearable
filterable
multiple
collapse-tags
collapse-tags-tooltip
style="width: 220px"
>
<el-option
v-for="item in logisticsMethodsList"
:key="item.code"
:label="item.basicsName"
:value="item.code"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search" ref="searchBtnRef"
>查询</el-button
>
<el-button type="success" @click="createWarehouse"
>新增</el-button
>
<el-button type="danger" @click="handleBatchDelete(null)"
>删除</el-button
>
</el-form-item>
</el-form>
</div>
<div class="user-content flex-1 flex-column overflow-hidden">
<div class="user-list flex-1 overflow-hidden">
<el-table
height="100%"
:data="tableData"
border
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" />
<el-table-column
type="index"
label="序号"
width="60"
align="center"
/>
<el-table-column
align="center"
label="分拣设备"
show-overflow-tooltip
prop="sortingFacility"
></el-table-column>
<el-table-column
align="center"
label="分拣口名称"
prop="sortingAreaName"
>
</el-table-column>
<el-table-column
align="center"
label="物流公司"
show-overflow-tooltip
prop="serviceCode"
></el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="{ row }">
<el-icon
size="24"
title="编辑"
color="#EF6C00"
style="cursor: pointer; vertical-align: middle"
@click="updateSorting(row)"
>
<Edit />
</el-icon>
<el-icon
size="24"
title="删除"
color="#f56c6c"
style="cursor: pointer; vertical-align: middle"
@click="handleBatchDelete(row)"
>
<Delete />
</el-icon>
</template>
</el-table-column>
</el-table>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination>
</div>
</el-tab-pane>
<el-tab-pane
label="按平台分拣(优先级低)"
name="2"
class="flex-column h-100 overflow-hidden"
>
<div class="header-filter-form">
<el-form inline :model="searchForm">
<el-form-item label="分拣设备">
<el-input
v-model.trim="searchForm.sortingFacility"
placeholder="分拣设备"
clearable
></el-input>
</el-form-item>
<el-form-item label="分拣口">
<el-select
v-model="searchForm.sortingArea"
clearable
style="width: 160px"
>
<el-option
v-for="item in sortingList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="平台">
<el-select
v-model="searchForm.serviceCode"
clearable
filterable
multiple
collapse-tags
collapse-tags-tooltip
popper-class="customize-select-style"
style="width: 200px"
>
<el-option
v-for="item in platformJson"
:key="item.type"
:label="item.type"
:value="item.type"
>
<img
:src="`/images/icon/${item.icon.split('/').pop()}`"
style="height: 20px; margin: 5px 10px 0 0"
/>
<span :title="item.type">{{ item.type }}</span></el-option
>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="success" @click="createWarehouse"
>新增</el-button
>
<el-button type="danger" @click="handleBatchDelete(null)"
>删除</el-button
>
</el-form-item>
</el-form>
</div>
<div class="user-content flex-1 flex-column overflow-hidden">
<div class="user-list flex-1 overflow-hidden">
<el-table
height="100%"
:data="tableData"
border
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" />
<el-table-column
type="index"
label="序号"
width="60"
align="center"
/>
<el-table-column
align="center"
label="分拣设备"
show-overflow-tooltip
prop="sortingFacility"
></el-table-column>
<el-table-column
align="center"
label="分拣口名称"
prop="sortingAreaName"
>
</el-table-column>
<el-table-column
align="center"
label="平台"
show-overflow-tooltip
prop="serviceCode"
></el-table-column>
<el-table-column label="操作" align="center" width="100">
<template #default="{ row }">
<el-icon
size="24"
title="编辑"
color="#EF6C00"
style="cursor: pointer; vertical-align: middle"
@click="updateSorting(row)"
>
<Edit />
</el-icon>
<el-icon
size="24"
title="删除"
color="#f56c6c"
style="cursor: pointer; vertical-align: middle"
@click="handleBatchDelete(row)"
>
<Delete />
</el-icon>
</template>
</el-table-column>
</el-table>
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 10px auto 0; text-align: right"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></ElPagination></div
></el-tab-pane>
</el-tabs>
<el-dialog
v-model="createData.show"
width="500px"
:title="createData.title"
>
<el-form ref="formRef" label-width="110px" :rules="rules" :model="form">
<el-form-item label="分拣设备" prop="sortingFacility">
<el-input
v-model.trim="form.sortingFacility"
placeholder="分拣设备"
clearable
></el-input>
</el-form-item>
<el-form-item label="分拣口" prop="sortingArea">
<div class="flex">
<el-select
v-model="form.sortingArea"
clearable
style="width: 320px"
@change="sortingChange"
>
<el-option
v-for="item in sortingList"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
&ensp;
<el-popover placement="bottom-start" width="700" trigger="click">
<img :src="sortingImg" alt="分拣口示意图" style="width: 100%" />
<template #reference>
<el-icon size="30" color="#606266" style="cursor: pointer">
<QuestionFilled />
</el-icon>
</template>
</el-popover>
<!-- <el-icon
size="30"
title="分拣口示意图"
style="cursor: pointer"
@click="mouseoverImg(ev, sortingImg, '700px', true, true)"
@mouseover="(ev:MouseEvent) => mouseoverImg(ev, sortingImg,'700px',true,true)"
@mouseleave="mouseleaveImg"
><QuestionFilled
/></el-icon> -->
</div>
</el-form-item>
<el-form-item
v-if="activeName == '1'"
label="物流公司"
prop="serviceCode"
>
<div class="flex">
<el-select
v-model="form.serviceCode"
style="width: 320px"
clearable
filterable
multiple
>
<el-option
v-for="item in logisticsMethodsList"
:key="item.code"
:label="item.basicsName"
:value="item.code"
></el-option>
</el-select>
<!-- &ensp;
<el-icon
color="#409eff"
size="30"
title="添加物流方式"
class="add-btn"
@click="addLogistics"
><CirclePlus
/></el-icon> -->
</div>
</el-form-item>
<el-form-item label="平台" v-else prop="serviceCode">
<el-select
v-model="form.serviceCode"
clearable
filterable
multiple
popper-class="customize-select-style"
>
<el-option
v-for="item in platformJson"
:key="item.type"
:label="item.type"
:value="item.type"
>
<img
:src="`/images/icon/${item.icon.split('/').pop()}`"
style="height: 20px; margin: 5px 10px 0 0"
/>
<span :title="item.type">{{ item.type }}</span></el-option
>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="createData.show = false">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<style scoped lang="scss"> <style scoped lang="scss">
.el-card { .user-list {
::v-deep(.el-card__body) { .table-container {
height: 100%; height: 100%;
overflow: hidden;
} }
} }
.customize-select-style {
.el-select-dropdown__list { .el-card {
width: 500px; ::v-deep(.el-card__body) {
display: flex; height: 100%;
flex-wrap: wrap;
.el-select-dropdown__item {
width: 160px;
}
} }
} }
.manage { .manage {
height: 100%; height: 100%;
display: flex; display: flex;
...@@ -742,10 +262,4 @@ useEnterKeyTrigger({ ...@@ -742,10 +262,4 @@ useEnterKeyTrigger({
} }
} }
} }
.add-btn :hover {
cursor: pointer;
}
.demo-tabs {
height: 100%;
}
</style> </style>
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