订单管理

This commit is contained in:
dev 2025-03-28 18:14:12 +08:00
parent 086fc44c7e
commit b4cc51c1d1
13 changed files with 583 additions and 166 deletions

View File

@ -13,6 +13,10 @@ export interface InquiryRequestVO {
* id
*/
requesterId: string | number;
/**
*
*/
requesterName: string;
/**
* ID列表JSON数组格式[101,202,303]

View File

@ -39,6 +39,18 @@ export const addLogisticsOrderDetail = (data: LogisticsOrderDetailForm) => {
});
};
/**
*
* @param data
*/
export const updateList = (data: LogisticsOrderDetailForm[]) => {
return request({
url: '/amz/logisticsOrderDetail/updateList',
method: 'post',
data: data
});
};
/**
*
* @param data

View File

@ -9,6 +9,8 @@ export interface LogisticsQuoteVO {
*/
userId: string | number;
logisticsName: string;
/**
* 使ISO国家代码如CN/US/GB
*/

View File

@ -0,0 +1,202 @@
<template>
<el-row>
<el-dialog v-model="visible" title="选择用户" width="800px" top="5vh" append-to-body>
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row>
<el-table
ref="tableRef"
:data="userList"
height="260px"
@row-click="clickRow"
@selection-change="handleSelectionChange"
@select="handleSelect"
@select-all="handleSelectAll"
style="width: 100%"
:header-cell-class-name="headerCellClassName"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="用户名称" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column label="邮箱" prop="email" :show-overflow-tooltip="true" />
<el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-if="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
</el-row>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSelectUser"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</template>
</el-dialog>
</el-row>
</template>
<script setup name="SelectUser" lang="ts">
import { allocatedUserList, authUserSelectAll, unallocatedUserList } from '@/api/system/role';
import { UserVO } from '@/api/system/user/types';
import { UserQuery } from '@/api/system/user/types';
import { AmazonStoreForm } from '@/api/amz/amazonStore/types';
import { updateAmazonStore } from '@/api/amz/amazonStore';
const props = defineProps({
roleId: {
type: [Number, String],
required: true
},
storeData: {
type: [Number, String],
required: true
}
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
const userList = ref<UserVO[]>([]);
const visible = ref(false);
const total = ref(0);
const userIds = ref<Array<string | number>>([]);
const queryParams = reactive<UserQuery>({
pageNum: 1,
pageSize: 10,
roleId: undefined,
userName: undefined,
phonenumber: undefined
});
const updateForm = ref<AmazonStoreForm>({
id: undefined,
userId: undefined
});
const tableRef = ref<ElTableInstance>();
const queryFormRef = ref<ElFormInstance>();
const show = () => {
queryParams.roleId = props.roleId;
updateForm.value.id = props.storeData;
console.log('updateForm:', updateForm.value);
getList();
visible.value = true;
};
/**
* 选择行
*/
const clickRow = (row: any) => {
// elebug
tableRef.value?.toggleRowSelection(row, false);
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: UserVO[]) => {
userIds.value = selection.map((item: UserVO) => item.userId);
console.log('userIds:', userIds.value);
};
/** 查询数据 */
const getList = async () => {
const res = await allocatedUserList(queryParams);
userList.value = res.rows;
total.value = res.total;
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
getList();
};
const emit = defineEmits(['ok']);
/**选择授权用户操作 */
const handleSelectUser = async () => {
const roleId = queryParams.roleId;
console.log('handleSelectUser:', userIds);
const ids = userIds.value.at(-1);
console.log('ids:', ids);
if (ids == '') {
proxy?.$modal.msgError('请选择要分配的用户');
return;
}
updateForm.value.userId = ids;
updateForm.value.id = props.storeData;
console.log('updateForm:', updateForm.value);
await updateAmazonStore(updateForm.value).finally(() => (visible.value = false));
proxy?.$modal.msgSuccess('分配成功');
emit('ok');
// await authUserSelectAll({ roleId, userIds: ids });
visible.value = false;
};
//
defineExpose({
show
});
//
const handleSelect = (selection, row) => {
//
if (tableRef.value.getSelectionRows().includes(row)) {
if (tableRef.value.getSelectionRows().length === 1) {
tableRef.value.clearSelection();
tableRef.value.toggleRowSelection(row, true);
} else {
tableRef.value.clearSelection();
tableRef.value.toggleRowSelection(row, true);
}
}
//
else {
// tableRef.value.clearSelection();
tableRef.value.toggleRowSelection(row, true);
}
};
//
const handleSelectAll = () => {
tableRef.value.clearSelection();
};
//
const headerCellClassName = ({ column }) => {
if (column.type === 'selection') {
return 'hidden-checkbox';
}
return '';
};
</script>
<style scoped>
.hidden-checkbox .el-checkbox {
display: none;
}
</style>

View File

@ -50,23 +50,23 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:amazonStore:add']">新增</el-button>
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['amz:amazonStore:add']">新增 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['amz:amazonStore:edit']"
>修改</el-button
>
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['amz:amazonStore:remove']"
>删除</el-button
>
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:amazonStore:export']">导出</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:amazonStore:export']">导出 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="collectAmzStore" v-hasPermi="['amz:amazonStore:export']">获取店铺数据</el-button>
<el-button type="warning" plain icon="Download" @click="collectAmzStore" v-hasPermi="['amz:amazonStore:export']">获取店铺数据 </el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -144,12 +144,14 @@
</div>
</template>
</el-dialog>
<assign-user ref="selectRef" :store-data="form.id" :role-id="yunyingRoleId" @ok="handleQuery" />
</div>
</template>
<script setup name="AmazonStore" lang="ts">
import { listAmazonStore, getAmazonStore, delAmazonStore, addAmazonStore, updateAmazonStore, collectAmzStoreData } from '@/api/amz/amazonStore';
import { AmazonStoreVO, AmazonStoreQuery, AmazonStoreForm } from '@/api/amz/amazonStore/types';
import AssignUser from '@/views/amz/amazonStore/assignUser.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -161,6 +163,9 @@ const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const yunyingRoleId = ref(4);
const selectRef = ref<InstanceType<typeof AssignUser>>();
const queryFormRef = ref<ElFormInstance>();
const amazonStoreFormRef = ref<ElFormInstance>();
@ -280,10 +285,11 @@ const handleAdd = () => {
const handleUpdate = async (row?: AmazonStoreVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getAmazonStore(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改亚马逊店铺信息';
form.value.id = _id;
console.log('form.value.id', _id);
selectRef.value?.show();
// dialog.visible = true;
// dialog.title = '';
};
/** 提交按钮 */

View File

@ -108,17 +108,20 @@
<el-table v-loading="loading" :data="inquiryRequestList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="询价单号" align="center" prop="inquiryNo" />
<el-table-column label="发起人id" align="center" prop="requesterId" />
<el-table-column label="发起人" align="center" prop="requesterName" />
<!-- <el-table-column label="目标物流商ID列表" align="center" prop="targetProviders" />-->
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="运输方式" align="center" prop="transportChannel" />
<el-table-column label="运输方式" align="center" prop="transportChannel">
<template #default="scope">
<dict-tag :options="biz_shipping_method" :value="scope.row.transportChannel" />
</template>
</el-table-column>
<el-table-column label="询价状态" align="center" prop="inquiryStatus" />
<el-table-column label="报价截止时间" align="center" prop="deadline" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.deadline, '{y}-{m}-{d} {h}:{m}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="渠道ID" align="center" prop="channelId" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="报价有效的开始日期" align="center" prop="effectiveStartTime" width="180">
<template #default="scope">
@ -224,7 +227,7 @@
<div class="kgprice">
<el-input-number v-model="quoteForm.price" :precision="2" :step="0.1" :min="1" :max="100">
<template #suffix>
<span>每公斤</span>
<span>/kg</span>
</template>
</el-input-number>
</div>
@ -255,9 +258,6 @@
<el-form-item label="报价备注" prop="remark">
<el-input v-model="quoteForm.remark" placeholder="请输入报价备注" />
</el-form-item>
<el-form-item label="渠道ID" prop="channelId">
<el-input v-model="quoteForm.channelId" placeholder="请输入渠道ID" disabled />
</el-form-item>
<el-form-item label="是否双清包税" prop="channelId">
<el-select v-model="quoteForm.isDdp" placeholder="选择是否双清包税" size="large" style="width: 240px">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
@ -283,6 +283,8 @@ import { addMostLogisticsQuote } from '@/api/amz/logisticsQuote';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_shipping_method } = toRefs<any>(proxy?.useDict('biz_shipping_method'));
const inquiryRequestList = ref<InquiryRequestVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
@ -366,7 +368,16 @@ const data = reactive<PageData<InquiryRequestForm, InquiryRequestQuery>>({
channelId: [{ required: true, message: '渠道ID不能为空', trigger: 'blur' }],
channelName: [{ required: true, message: '渠道名称不能为空', trigger: 'blur' }],
effectiveStartTime: [{ required: true, message: '报价有效的开始日期不能为空', trigger: 'blur' }],
effectiveEndTime: [{ required: true, message: '报价有效的结束日期不能为空', trigger: 'blur' }]
effectiveEndTime: [{ required: true, message: '报价有效的结束日期不能为空', trigger: 'blur' }],
price: [{ required: true, message: '基础价格不能为空', trigger: 'blur' }],
leadTime: [{ required: true, message: '时效不能为空', trigger: 'blur' }],
surcharge: [{ required: true, message: '附加费不能为空', trigger: 'blur' }],
quoteDate: [{ required: true, message: '报价生效日期不能为空', trigger: 'blur' }],
isSubmitted: [{ required: true, message: '提交状态不能为空', trigger: 'blur' }],
remark: [{ required: true, message: '报价备注不能为空', trigger: 'blur' }],
channelType: [{ required: true, message: '渠道类型不能为空', trigger: 'change' }],
isDdp: [{ required: true, message: '是否双清包税不能为空', trigger: 'blur' }],
unit: [{ required: true, message: '单位不能为空', trigger: 'blur' }]
}
});

View File

@ -76,7 +76,7 @@
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="FBA货件编号" align="center" prop="fbaShipmentId" />
<el-table-column label="订单编号" align="center" prop="orderId" />
<el-table-column label="物流商ID" align="center" prop="logisticsProviderId" />
<el-table-column label="创建日期" align="center" prop="createTime" />
<el-table-column label="物流商名称" align="center" prop="logisticsProviderName" />
<el-table-column label="物流渠道" align="center" prop="logisticsChannel" />
<el-table-column label="目的地仓库名称或编码" align="center" prop="destination" />
@ -103,20 +103,12 @@
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['amz:logisticsOrder:remove']"></el-button>
</el-tooltip>
<el-tooltip content="查看订单明细" placement="top">
<el-button type="primary" @click="openDetail(scope.row)" v-hasRoles="['wuliu']"> 编辑订单明细</el-button>
</el-tooltip>
<el-button type="primary" @click="openDetail(scope.row)" v-hasRoles="['wuliu']"> 编辑订单明细</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="detailTotal"
v-model:page="queryDetailParams.pageNum"
v-model:limit="queryDetailParams.pageSize"
@pagination="getList"
/>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改物流订单对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
@ -127,6 +119,9 @@
<el-form-item label="订单编号" prop="orderId">
<el-input v-model="form.orderId" placeholder="请输入订单编号" />
</el-form-item>
<el-form-item label="订单编号" prop="orderId">
<el-input v-model="form.orderId" placeholder="请输入订单编号" />
</el-form-item>
<el-form-item label="物流商ID" prop="logisticsProviderId">
<el-input v-model="form.logisticsProviderId" placeholder="请输入物流商ID" />
</el-form-item>
@ -176,15 +171,15 @@
<pagination
v-show="detailTotal > 0"
:total="detailTotal"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
v-model:page="queryDetailParams.pageNum"
v-model:limit="queryDetailParams.pageSize"
@pagination="getDetailList"
/>
</template>
<template #footer>
<div style="flex: auto">
<el-button @click="cancelDataClick">cancel</el-button>
<el-button type="primary" @click="submitDataClick">confirm</el-button>
<el-button @click="hotTableDrawer = false">取消</el-button>
<el-button type="primary" @click="updateCheckDatas">提交选中数据</el-button>
</div>
</template>
</el-drawer>
@ -199,11 +194,14 @@ import { computed, ref, watch } from 'vue';
import { HotTable } from '@handsontable/vue3';
import { checkPermi } from '@/utils/permission';
import { LogisticsOrderDetailVO } from '@/api/amz/logisticsOrderDetail/types';
import { listLogisticsOrderDetail } from '@/api/amz/logisticsOrderDetail';
import { listLogisticsOrderDetail, updateList } from '@/api/amz/logisticsOrderDetail';
import 'handsontable/dist/handsontable.full.min.css';
// import 'handsontable/styles/ht-theme-horizon.css';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_logistics_status } = toRefs<any>(proxy?.useDict('biz_logistics_status'));
//
registerAllModules();
@ -225,11 +223,38 @@ const processedData = computed(() => {
const hotTableDrawer = ref(false);
const statusOptions = computed(() => biz_logistics_status.value.map((item) => item.label));
//
const valueToLabelMap = computed(() => {
return biz_logistics_status.value.reduce((map, item) => {
map[item.value] = item.label;
return map;
}, {});
});
const labelTovalueMap = computed(() => {
return biz_logistics_status.value.reduce((map, item) => {
map[item.label] = item.value;
return map;
}, {});
});
// -------
const hotSettings = ref({
licenseKey: 'non-commercial-and-evaluation',
// afterValidate: (isValid, value, row, prop, source) => {
// if (!isValid) {
// //
// console.log('isValid:', isValid, 'value:', value, 'row:', row, 'prop:', prop, 'source:', source);
// const oldValue = hotTable.value.hotInstance.getDataAtCell(row, prop);
// console.log(':', oldValue);
// hotTable.value.hotInstance.setDataAtRowProp(row, prop, oldValue);
// }
// },
theme: 'ht-theme-horizon',
manualColumnResize: true, // false
rowHeaders: false, //
rowHeaders: true, //
filters: true, //
// dropdownMenu: true, //
// contextMenu: true, //
@ -253,13 +278,25 @@ const hotSettings = ref({
},
afterChange: (changes) => {
if (!changes) return;
console.log('changes:', changes);
// console.log('changes:', changes);
// changes.forEach(([row, prop, oldVal, newVal]) => {
// console.log(':', row);
// console.log(':', prop);
// console.log(':', oldVal);
// console.log(':', newVal);
// });
changes.forEach(([row, prop, oldVal, newVal]) => {
console.log('修改的行:', row);
console.log('修改的列:', prop);
console.log('旧值:', oldVal);
console.log('新值:', newVal);
logisticsOrderDetailList.value[row][prop] = newVal;
if (prop === 'logisticsStatus') {
logisticsOrderDetailList.value[row].logisticsStatus = labelTovalueMap.value[newVal];
}
});
console.log('logisticsOrderDetailList.value:', logisticsOrderDetailList.value);
},
colHeaders: [
'选择',
@ -273,7 +310,6 @@ const hotSettings = ref({
'计划数量',
'实际货件数量',
'物流追踪号',
'供应商称重',
'物流商计重',
'称重差异',
'物流单价',
@ -291,6 +327,7 @@ const hotSettings = ref({
//
type: 'checkbox',
className: 'htCenter',
data: 'checked',
width: 55
},
{ data: 'orderId', className: 'htCenter', readOnly: true },
@ -304,7 +341,6 @@ const hotSettings = ref({
{ data: 'plannedQuantity', className: 'htCenter', readOnly: true }, //
{ data: 'actualShipmentQuantity', className: 'htCenter', readOnly: true }, //
{ data: 'trackingNumber', className: 'htCenter', readOnly: false }, //
{ data: 'supplierWeight', className: 'htCenter', readOnly: true }, //
{ data: 'logisticsWeight', className: 'htCenter', readOnly: true }, //
{
data: 'weightDiff', //
@ -325,20 +361,53 @@ const hotSettings = ref({
data: 'logisticsStatus',
className: 'htCenter',
readOnly: false,
type: 'dropdown',
source: ['水果', '蔬菜', '肉类']
type: 'select',
selectOptions: statusOptions,
strict: false, // label value
renderer: (instance, td, row, col, prop, value) => {
// label value
td.textContent = valueToLabelMap.value[value] || value;
return td;
}
}, //
{
//
data: 'estimatedDeliveryDateFormatted',
className: 'htCenter',
width: 180
data: 'estimatedDeliveryDate',
type: 'date', //
dateFormat: 'YYYY-MM-DD', //
correctFormat: true, //
// locale: 'zh-CN', //
// className: 'htCenter', //
validator: (value, callback) => {
if (value === '') {
callback(true); //
return;
}
// JS
const regex = /^\d{4}-\d{2}-\d{2}$/;
console.log('校验日期格式和有效性');
if (!regex.test(value)) {
callback(false);
console.log('校验日期格式和有效性失败');
return;
}
const [year, month, day] = value.split('-').map(Number);
const date = new Date(year, month - 1, day);
const isValid = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
console.log('校验日期格式和有效性', isValid);
callback(isValid);
}
},
{
//
data: 'actualDeliveryDateFormatted',
className: 'htCenter',
width: 180
data: 'actualDeliveryDate',
type: 'date', //
dateFormat: 'YYYY-MM-DD', //
correctFormat: true, //
locale: 'zh-CN', //
className: 'htCenter' //
},
{
//
@ -512,12 +581,36 @@ const getList = async () => {
const getDetailList = async () => {
detailLoading.value = true;
const res = await listLogisticsOrderDetail(queryParams.value);
logisticsOrderDetailList.value = res.rows;
const res = await listLogisticsOrderDetail(queryDetailParams.value);
logisticsOrderDetailList.value = res.rows.map((item) => ({
...item,
checked: false //
}));
console.log('logisticsOrderDetailList', logisticsOrderDetailList);
detailTotal.value = res.total;
detailLoading.value = false;
};
const updateCheckDatas = async () => {
//
const checkedRows = logisticsOrderDetailList.value.filter((row) => row.checked);
console.log('checkedRows', checkedRows);
if (checkedRows.length === 0) {
ElMessage.warning('请选择要修改的行');
return;
}
const res = await updateList(checkedRows);
console.log('res', res);
if (res.code === 200) {
ElMessage.success('更新成功');
getDetailList();
} else {
ElMessage.error('更新失败');
}
};
/** 取消按钮 */
const cancel = () => {
reset();
@ -599,10 +692,11 @@ const openDetail = async (row?: LogisticsOrderVO) => {
console.log(_ids);
detailLoading.value = true;
queryDetailParams.value.orderId = row.orderId;
const res = await listLogisticsOrderDetail(queryDetailParams.value);
logisticsOrderDetailList.value = res.rows;
detailTotal.value = res.total;
detailLoading.value = false;
// const res = await listLogisticsOrderDetail(queryDetailParams.value);
// logisticsOrderDetailList.value = res.rows;
// detailTotal.value = res.total;
// detailLoading.value = false;
getDetailList();
};
/** 导出按钮操作 */

View File

@ -3,7 +3,7 @@
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="180px">
<el-form-item label="订单号" prop="orderId">
<el-input v-model="queryParams.orderId" placeholder="请输入订单号" clearable @keyup.enter="handleQuery" />
</el-form-item>
@ -25,36 +25,9 @@
<el-form-item label="目的地仓库" prop="destination">
<el-input v-model="queryParams.destination" placeholder="请输入目的地仓库" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="计划数量" prop="plannedQuantity">
<el-input v-model="queryParams.plannedQuantity" placeholder="请输入计划数量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="实际货件数量" prop="shipmentQuantity">
<el-input v-model="queryParams.shipmentQuantity" placeholder="请输入实际货件数量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流追踪号" prop="trackingNumber">
<el-input v-model="queryParams.trackingNumber" placeholder="请输入物流追踪号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="供应商称重" prop="supplierWeight">
<el-input v-model="queryParams.supplierWeight" placeholder="请输入供应商称重" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流商计重" prop="logisticsWeight">
<el-input v-model="queryParams.logisticsWeight" placeholder="请输入物流商计重" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="称重差异" prop="weightDiff">
<el-input v-model="queryParams.weightDiff" placeholder="请输入称重差异" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流单价" prop="pricePerKg">
<el-input v-model="queryParams.pricePerKg" placeholder="请输入物流单价" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="物流计价重量" prop="logisticsCalculationPrice">
<el-input v-model="queryParams.logisticsCalculationPrice" placeholder="请输入物流计价重量" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="其他物流费用" prop="otherFee">
<el-input v-model="queryParams.otherFee" placeholder="请输入其他物流费用" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="费用合计" prop="totalFee">
<el-input v-model="queryParams.totalFee" placeholder="请输入费用合计" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="预计签收日期" prop="estimatedDeliveryDate">
<el-date-picker
clearable
@ -105,7 +78,13 @@
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['amz:logisticsOrderDetail:export']">导出 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="openEdit" v-hasPermi="['amz:logisticsOrderDetail:export']"
<el-button
type="warning"
plain
icon="Download"
@click="openEdit"
v-hasRoles="['superadmin']"
v-hasPermi="['amz:logisticsOrderDetail:export']"
>打开编辑模式
</el-button>
</el-col>
@ -181,8 +160,8 @@
</el-drawer>
<!-- 添加或修改物流订单明细按箱子维度存储对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="logisticsOrderDetailFormRef" :model="form" :rules="rules" label-width="80px">
<el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
<el-form ref="logisticsOrderDetailFormRef" :model="form" :rules="rules" label-width="180px">
<el-form-item label="订单号" prop="orderId">
<el-input v-model="form.orderId" placeholder="请输入订单号" disabled />
</el-form-item>
@ -234,6 +213,18 @@
<el-form-item label="费用合计" prop="totalFee">
<el-input v-model="form.totalFee" placeholder="请输入费用合计" />
</el-form-item>
<el-form-item label="物流状态" prop="logisticsStatus">
<el-select v-model="form.logisticsStatus" clearable placeholder="物流状态">
<el-option
v-model="form.logisticsStatus"
v-for="dict in biz_logistics_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="预计签收日期" prop="estimatedDeliveryDate">
<el-date-picker
clearable
@ -284,7 +275,7 @@ import { registerAllModules } from 'handsontable/registry';
import 'handsontable/dist/handsontable.full.min.css';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_logistics_status } = toRefs<any>(proxy?.useDict('biz_logistics_status'));
const logisticsOrderDetailList = ref<LogisticsOrderDetailVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);

View File

@ -32,7 +32,7 @@
<el-input v-model="queryParams.unit" placeholder="请输入单位" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="checkStatus">搜索</el-button>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -89,12 +89,24 @@
<el-table v-loading="loading" :data="logisticsQuoteList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="物流商用户ID" align="center" prop="userId" />
<el-table-column label="物流商" align="center" prop="logisticsName" />
<el-table-column label="目的地" align="center" prop="destination" />
<el-table-column label="渠道名称" align="center" prop="channelName" />
<el-table-column label="基础价格" align="center" prop="price" />
<el-table-column label="时效" align="center" prop="leadTime" />
<el-table-column label="附加费" align="center" prop="surcharge" />
<el-table-column label="基础价格" align="center" prop="price">
<template #default="scope">
<span>{{ scope.row.price + '元/kg' }}</span>
</template>
</el-table-column>
<el-table-column label="时效" align="center" prop="leadTime">
<template #default="scope">
<span>{{ scope.row.leadTime + '天' }}</span>
</template>
</el-table-column>
<el-table-column label="附加费" align="center" prop="surcharge">
<template #default="scope">
<span>{{ scope.row.surcharge + '元' }}</span>
</template>
</el-table-column>
<el-table-column label="报价生效日期" align="center" prop="quoteDate" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.quoteDate, '{y}-{m}-{d}') }}</span>
@ -106,8 +118,16 @@
</template>
</el-table-column>
<el-table-column label="报价备注" align="center" prop="remark" />
<el-table-column label="渠道类型" align="center" prop="channelType" />
<el-table-column label="是否双清包税" align="center" prop="isDdp" />
<el-table-column label="渠道类型" align="center" prop="channelType">
<template #default="scope">
<dict-tag :options="biz_channel_type" :value="scope.row.channelType" />
</template>
</el-table-column>
<el-table-column label="是否双清包税" align="center" prop="isDdp">
<template #default="scope">
<dict-tag :options="sys_yes_no" :value="scope.row.isDdp" />
</template>
</el-table-column>
<el-table-column label="单位" align="center" prop="unit" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
@ -168,9 +188,6 @@
<el-form-item label="报价备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入报价备注" />
</el-form-item>
<el-form-item label="渠道ID" prop="channelId">
<el-input v-model="form.channelId" placeholder="请输入渠道ID" />
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" placeholder="请输入单位" />
</el-form-item>
@ -198,6 +215,8 @@ import { LogisticsQuoteVO, LogisticsQuoteQuery, LogisticsQuoteForm } from '@/api
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { biz_channel_type } = toRefs<any>(proxy?.useDict('biz_channel_type'));
const { sys_yes_no } = toRefs<any>(proxy?.useDict('sys_yes_no'));
const logisticsQuoteList = ref<LogisticsQuoteVO[]>([]);

View File

@ -161,9 +161,6 @@
<!-- 添加或修改货件计划对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="shipmentPlanFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="主键ID" prop="id">
<el-input v-model="form.id" placeholder="请输入主键ID" />
</el-form-item>
<el-form-item label="关联系统ID" prop="sid">
<el-input v-model="form.sid" placeholder="请输入关联系统ID" />
</el-form-item>
@ -282,26 +279,35 @@
<el-input v-model="currentDes" disabled />
</el-form-item>
<el-form-item label="渠道选择">
<el-collapse v-model="activeCollapse">
<!-- 遍历国家分组 -->
<el-collapse-item v-for="(countryGroup, country) in groupedChannels" :key="country" :title="getCountryName(country)" :name="country">
<!-- 遍历运输方式 -->
<div v-for="(methodGroup, method) in countryGroup" :key="method">
<div class="shipping-method-title">
{{ getShippingMethodName(method) }}
</div>
<el-radio-group v-model="selectedChannel" @change="handleChannelSelect">
<!-- 遍历具体渠道 -->
<div v-for="channel in methodGroup" :key="channel.id" class="channel-item">
<el-radio :label="channel.id">
{{ getChannelLabel(channel.channelName) }}
</el-radio>
<div class="channel-description">{{ channel.description }}</div>
</div>
</el-radio-group>
</div>
</el-collapse-item>
</el-collapse>
<!-- <el-collapse v-model="activeCollapse">-->
<!-- &lt;!&ndash; 遍历国家分组 &ndash;&gt;-->
<!-- <el-collapse-item v-for="(countryGroup, country) in groupedChannels" :key="country" :title="getCountryName(country)" :name="country">-->
<!-- &lt;!&ndash; 遍历运输方式 &ndash;&gt;-->
<!-- <div v-for="(methodGroup, method) in countryGroup" :key="method">-->
<!-- <div class="shipping-method-title">-->
<!-- {{ getShippingMethodName(method) }}-->
<!-- </div>-->
<!-- <el-radio-group v-model="selectedChannel" @change="handleChannelSelect">-->
<!-- &lt;!&ndash; 遍历具体渠道 &ndash;&gt;-->
<!-- <div v-for="channel in methodGroup" :key="channel.id" class="channel-item">-->
<!-- <el-radio :label="channel.id">-->
<!-- {{ getChannelLabel(channel.channelName) }}-->
<!-- </el-radio>-->
<!-- <div class="channel-description">{{ channel.description }}</div>-->
<!-- </div>-->
<!-- </el-radio-group>-->
<!-- </div>-->
<!-- </el-collapse-item>-->
<!-- </el-collapse>-->
<el-cascader
v-model="selectedChannel"
placeholder="请选择渠道"
:props="{ emitPath: false }"
:options="groupedChannels"
@change="cascaderChange"
:show-all-levels="false"
filterable
/>
</el-form-item>
<el-form-item label="日期选择">
<el-date-picker v-model="shipDate" type="date" placeholder="Pick a day" value-format="YYYY-MM-DD" :size="size" />
@ -586,6 +592,11 @@ function cancelClick() {
drawer.value = false;
}
const cascaderChange = (value) => {
console.log(value);
console.log('selectedChannel', selectedChannel);
};
function confirmClick() {
ElMessageBox.confirm(`Are you confirm to chose ${radio1.value} ?`)
.then(() => {
@ -623,32 +634,76 @@ const getAllChannelData = async () => {
console.log('groupedChannels:', groupedChannels.value);
};
//
//
const countryMap = {
us: '美国'
//
};
//
const shippingMethodMap = {
air: '空运',
sea: '海运'
//
};
function transformChannels(channels) {
const result = [];
const countryGroups = {}; //
channels.forEach((channel) => {
const { country, shippingMethod, channelName, id } = channel;
//
const countryValue = country;
const countryLabel = countryMap[country] || country;
if (!countryGroups[countryValue]) {
countryGroups[countryValue] = {
value: countryValue,
label: countryLabel,
children: []
};
result.push(countryGroups[countryValue]);
}
//
const methodValue = shippingMethod;
const methodLabel = shippingMethodMap[shippingMethod] || shippingMethod;
let methodNode = countryGroups[countryValue].children.find((m) => m.value === methodValue);
if (!methodNode) {
methodNode = {
value: methodValue,
label: methodLabel,
children: []
};
countryGroups[countryValue].children.push(methodNode);
}
//
methodNode.children.push({
value: id,
label: channelName
});
});
return result;
}
const currentDes = ref('');
const currentFBAData = ref('');
//
const groupedChannels = computed(() => {
return channelTableData.value.reduce((acc, channel) => {
const country = channel.country;
const method = channel.shippingMethod;
if (!acc[country]) acc[country] = {};
if (!acc[country][method]) acc[country][method] = [];
acc[country][method].push(channel);
return acc;
}, {});
// return channelTableData.value.reduce((acc, channel) => {
// const country = channel.country;
// const method = channel.shippingMethod;
//
// if (!acc[country]) acc[country] = {};
// if (!acc[country][method]) acc[country][method] = [];
//
// acc[country][method].push(channel);
// return acc;
// }, {});
return transformChannels(channelTableData.value);
});
// +

View File

@ -8,12 +8,16 @@
<el-form-item v-if="tenantEnabled" prop="tenantId">
<el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="company" class="el-input__icon input-icon" />
</template>
</el-select>
</el-form-item>
<el-form-item prop="username">
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="user" class="el-input__icon input-icon" />
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
@ -25,7 +29,9 @@
:placeholder="proxy.$t('login.password')"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="password" class="el-input__icon input-icon" />
</template>
</el-input>
</el-form-item>
<el-form-item v-if="captchaEnabled" prop="code">
@ -37,30 +43,32 @@
style="width: 63%"
@keyup.enter="handleLogin"
>
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
<template #prefix>
<svg-icon icon-class="validCode" class="el-input__icon input-icon" />
</template>
</el-input>
<div class="login-code">
<img :src="codeUrl" class="login-code-img" @click="getCode" />
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
<el-form-item style="float: right">
<el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
<svg-icon icon-class="wechat" />
</el-button>
<el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">
<svg-icon icon-class="maxkey" />
</el-button>
<el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">
<svg-icon icon-class="topiam" />
</el-button>
<el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">
<svg-icon icon-class="gitee" />
</el-button>
<el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">
<svg-icon icon-class="github" />
</el-button>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }} </el-checkbox>
<!-- <el-form-item style="float: right">-->
<!-- <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">-->
<!-- <svg-icon icon-class="wechat" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">-->
<!-- <svg-icon icon-class="maxkey" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">-->
<!-- <svg-icon icon-class="topiam" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">-->
<!-- <svg-icon icon-class="gitee" />-->
<!-- </el-button>-->
<!-- <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">-->
<!-- <svg-icon icon-class="github" />-->
<!-- </el-button>-->
<!-- </el-form-item>-->
<el-form-item style="width: 100%">
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin">
<span v-if="!loading">{{ proxy.$t('login.login') }}</span>
@ -95,8 +103,8 @@ const { t } = useI18n();
const loginForm = ref<LoginData>({
tenantId: '000000',
username: 'admin',
password: 'admin123',
username: '',
password: '',
rememberMe: false,
code: '',
uuid: ''

View File

@ -14,27 +14,38 @@
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<svg-icon icon-class="user" />用户名称
<svg-icon icon-class="user" />
用户名称
<div class="pull-right">{{ state.user.userName }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone" />手机号码
<svg-icon icon-class="user" />
用户昵称
<div class="pull-right">{{ state.user.nickName }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone" />
手机号码
<div class="pull-right">{{ state.user.phonenumber }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="email" />用户邮箱
<svg-icon icon-class="email" />
用户邮箱
<div class="pull-right">{{ state.user.email }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="tree" />所属部门
<svg-icon icon-class="tree" />
所属部门
<div v-if="state.user.deptName" class="pull-right">{{ state.user.deptName }} / {{ state.postGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="peoples" />所属角色
<svg-icon icon-class="peoples" />
所属角色
<div class="pull-right">{{ state.roleGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="date" />创建日期
<svg-icon icon-class="date" />
创建日期
<div class="pull-right">{{ state.user.createTime }}</div>
</li>
</ul>
@ -55,9 +66,9 @@
<el-tab-pane label="修改密码" name="resetPwd">
<resetPwd />
</el-tab-pane>
<el-tab-pane label="第三方应用" name="thirdParty">
<thirdParty :auths="state.auths" />
</el-tab-pane>
<!-- <el-tab-pane label="第三方应用" name="thirdParty">-->
<!-- <thirdParty :auths="state.auths" />-->
<!-- </el-tab-pane>-->
<el-tab-pane label="在线设备" name="onlineDevice">
<onlineDevice :devices="state.devices" />
</el-tab-pane>
@ -80,6 +91,7 @@ import { getOnline } from '@/api/monitor/online';
import { UserVO } from '@/api/system/user/types';
const activeTab = ref('userinfo');
interface State {
user: Partial<UserVO>;
roleGroup: string;
@ -87,6 +99,7 @@ interface State {
auths: any;
devices: any;
}
const state = ref<State>({
user: {},
roleGroup: '',

View File

@ -1,8 +1,8 @@
<template>
<el-form ref="userRef" :model="userForm" :rules="rules" label-width="80px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="userForm.nickName" maxlength="30" />
</el-form-item>
<!-- <el-form-item label="用户昵称" prop="nickName">-->
<!-- <el-input v-model="userForm.nickName" maxlength="30" />-->
<!-- </el-form-item>-->
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="userForm.phonenumber" maxlength="11" />
</el-form-item>