no message
parent
d308c16400
commit
bf33b23154
|
|
@ -5,6 +5,7 @@ const { createConfirm } = useMessage();
|
||||||
|
|
||||||
enum Api {
|
enum Api {
|
||||||
list = '/base/area/list',
|
list = '/base/area/list',
|
||||||
|
queryById='/base/area/queryById',
|
||||||
save = '/base/area/add',
|
save = '/base/area/add',
|
||||||
edit = '/base/area/edit',
|
edit = '/base/area/edit',
|
||||||
deleteOne = '/base/area/delete',
|
deleteOne = '/base/area/delete',
|
||||||
|
|
@ -30,6 +31,11 @@ export const getImportUrl = Api.importExcel;
|
||||||
*/
|
*/
|
||||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id查询
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const queryById = (params) => defHttp.get({ url: Api.queryById, params });
|
||||||
/**
|
/**
|
||||||
* 删除单个
|
* 删除单个
|
||||||
* @param params
|
* @param params
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!-- 库区下拉选择-->
|
<!-- 库区选择 -->
|
||||||
<template>
|
<template>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="selectedValue"
|
v-model:value="selectedValue"
|
||||||
|
|
@ -12,350 +12,407 @@
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
@focus="handleFocus"
|
@focus="handleFocus"
|
||||||
@popupScroll="handlePopupScroll"
|
@popup-scroll="handlePopupScroll"
|
||||||
:getPopupContainer="getParentContainer"
|
:getPopupContainer="getParentContainer"
|
||||||
v-bind="attrs"
|
v-bind="attrs"
|
||||||
>
|
>
|
||||||
<template #notFoundContent>
|
<template #notFoundContent>
|
||||||
<a-spin v-if="loading" size="small" />
|
|
||||||
<span v-else>暂无库区数据</span>
|
|
||||||
</template>
|
</template>
|
||||||
<a-select-option v-for="option in areaOptions" :key="option.id" :value="getOptionValue(option)">
|
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
||||||
{{ getOptionLabel(option) }}
|
{{ getOptionLabel(option) }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch, computed, onMounted } from 'vue';
|
import { defineComponent, ref, watch, computed, onMounted } from 'vue';
|
||||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { defHttp } from '/@/utils/http/axios';
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
import { setPopContainer } from '/@/utils';
|
import { queryById } from '@/views/base/area/Area.api';
|
||||||
import { debounce } from 'lodash-es';
|
import { setPopContainer } from '/@/utils';
|
||||||
|
import { debounce } from 'lodash-es';
|
||||||
|
|
||||||
// 库区数据接口
|
// 库区数据接口
|
||||||
interface Area {
|
interface Area {
|
||||||
id: string;
|
id: string;
|
||||||
areaCode: string;
|
areaCode: string;
|
||||||
areaName: string;
|
areaName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
//响应数据接口
|
//响应数据接口
|
||||||
interface ResponseData {
|
interface ResponseData {
|
||||||
records: Area[];
|
records: Area[];
|
||||||
total: number;
|
total: number;
|
||||||
size: number;
|
size: number;
|
||||||
current: number;
|
current: number;
|
||||||
page: number;
|
page: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AreaSelect',
|
name: 'AreaSelect',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
// 选中值,支持v-model
|
// 选中值,支持v-model
|
||||||
value: propTypes.oneOfType([propTypes.string, propTypes.array, propTypes.object]),
|
value: propTypes.oneOfType([propTypes.string, propTypes.array, propTypes.object]),
|
||||||
// 占位符
|
// 占位符
|
||||||
placeholder: propTypes.string.def('请选择库区'),
|
placeholder: propTypes.string.def('请选择库区'),
|
||||||
// 是否多选
|
// 是否多选
|
||||||
multiple: propTypes.bool.def(false),
|
multiple: propTypes.bool.def(false),
|
||||||
// 是否异步加载数据
|
// 是否异步加载数据
|
||||||
async: propTypes.bool.def(true),
|
async: propTypes.bool.def(true),
|
||||||
// 分页大小
|
// 分页大小
|
||||||
pageSize: propTypes.number.def(20),
|
pageSize: propTypes.number.def(10),
|
||||||
// 弹出层容器
|
// 弹出层容器
|
||||||
popContainer: propTypes.string,
|
popContainer: propTypes.string,
|
||||||
// 自定义弹出层容器函数
|
// 自定义弹出层容器函数
|
||||||
getPopupContainer: {
|
getPopupContainer: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: (node: HTMLElement) => node?.parentNode,
|
default: (node: HTMLElement) => node?.parentNode,
|
||||||
},
|
|
||||||
// 是否立即触发change事件
|
|
||||||
immediateChange: propTypes.bool.def(false),
|
|
||||||
// 返回值类型: 'id'(默认) | 'object' | 其他字段名
|
|
||||||
returnValue: propTypes.string.def('id'),
|
|
||||||
//默认启用
|
|
||||||
izActive: propTypes.number.def(1),
|
|
||||||
},
|
},
|
||||||
emits: ['change', 'update:value', 'optionsLoaded'],
|
// 是否立即触发change事件
|
||||||
setup(props, { emit }) {
|
immediateChange: propTypes.bool.def(false),
|
||||||
const areaOptions = ref<Area[]>([]);
|
// 返回值类型: 'id'(默认) | 'object' | 其他字段名
|
||||||
const loading = ref<boolean>(false);
|
returnValue: propTypes.string.def('id'),
|
||||||
const allAreas = ref<Area[]>([]);
|
//默认启用
|
||||||
const attrs = useAttrs({ excludeDefaultKeys: false });
|
izActive: propTypes.number.def(1),
|
||||||
|
//默认未删除
|
||||||
|
delFlag:propTypes.number.def(0)
|
||||||
|
},
|
||||||
|
emits: ['change', 'update:value', 'optionsLoaded'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const Options = ref<Area[]>([]);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const allAreas = ref<Area[]>([]);
|
||||||
|
const attrs = useAttrs({ excludeDefaultKeys: false });
|
||||||
|
|
||||||
// 分页相关
|
// 分页相关
|
||||||
const pageNo = ref(1);
|
const pageNo = ref(1);
|
||||||
const isHasData = ref(true);
|
const isHasData = ref(true);
|
||||||
const scrollLoading = ref(false);
|
const scrollLoading = ref(false);
|
||||||
const searchKeyword = ref('');
|
const searchKeyword = ref('');
|
||||||
|
|
||||||
// 选中值
|
// 选中值
|
||||||
const selectedValue = ref<string | string[] | undefined>(undefined);
|
const selectedValue = ref<string | string[] | undefined>(undefined);
|
||||||
|
|
||||||
// 未找到内容
|
// 未找到内容
|
||||||
const notFoundContent = computed(() => {
|
const notFoundContent = computed(() => {
|
||||||
return loading.value ? undefined : null;
|
return loading.value ? undefined : '暂无数据';
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取选项显示文本 - 始终显示完整格式
|
* 获取选项显示文本 - 始终显示完整格式
|
||||||
*/
|
*/
|
||||||
function getOptionLabel(option: Area) {
|
function getOptionLabel(option: Area) {
|
||||||
return `${option.areaCode} - ${option.areaName}`;
|
return `${option.areaCode} - ${option.areaName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取选项值 - 根据returnValue确定实际存储的值
|
||||||
|
*/
|
||||||
|
function getOptionValue(option: Area) {
|
||||||
|
if (props.returnValue === 'object') {
|
||||||
|
return option.id; // 对于object类型,仍然使用id作为选项值,但在change事件中返回完整对象
|
||||||
|
} else if (props.returnValue === 'id') {
|
||||||
|
return option.id;
|
||||||
|
} else {
|
||||||
|
return option[props.returnValue as keyof Area] as string;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取选项值 - 根据returnValue确定实际存储的值
|
* 获取弹出层容器
|
||||||
*/
|
*/
|
||||||
function getOptionValue(option: Area) {
|
function getParentContainer(node: HTMLElement) {
|
||||||
if (props.returnValue === 'object') {
|
if (props.popContainer) {
|
||||||
return option.id; // 对于object类型,仍然使用id作为选项值,但在change事件中返回完整对象
|
return setPopContainer(node, props.popContainer);
|
||||||
} else if (props.returnValue === 'id') {
|
} else {
|
||||||
return option.id;
|
if (typeof props.getPopupContainer === 'function') {
|
||||||
|
return props.getPopupContainer(node);
|
||||||
} else {
|
} else {
|
||||||
return option[props.returnValue as keyof Area] as string;
|
return node?.parentNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取弹出层容器
|
* 过滤选项 - 禁用前端过滤,使用后端搜索
|
||||||
*/
|
*/
|
||||||
function getParentContainer(node: HTMLElement) {
|
function filterOption(_input: string, _option: any) {
|
||||||
if (props.popContainer) {
|
return true; // 禁用前端过滤,完全依赖后端搜索
|
||||||
return setPopContainer(node, props.popContainer);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保库区唯一性的辅助函数
|
||||||
|
*/
|
||||||
|
function ensureUnique(Areas: Area[], newArea: Area): Area[] {
|
||||||
|
// 如果已经存在相同id的库区,先移除旧的再添加新的
|
||||||
|
const filtered = Areas.filter(Area => Area.id !== newArea.id);
|
||||||
|
return [newArea, ...filtered];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取库区数据
|
||||||
|
*/
|
||||||
|
const queryData = async (page = 1, keyword = '', isSearch = false) => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
const res = await defHttp.get<ResponseData>({
|
||||||
|
url: '/base/Area/list',
|
||||||
|
params: {
|
||||||
|
pageSize: props.pageSize,
|
||||||
|
pageNo: page,
|
||||||
|
keyword: keyword,
|
||||||
|
izActive: props.izActive,
|
||||||
|
delFlag: props.delFlag
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const records = res.records || [];
|
||||||
|
|
||||||
|
if (page === 1 || isSearch) {
|
||||||
|
// 第一页或搜索时,重置数据
|
||||||
|
allAreas.value = records;
|
||||||
|
Options.value = records;
|
||||||
} else {
|
} else {
|
||||||
if (typeof props.getPopupContainer === 'function') {
|
// 滚动加载时,追加数据(确保不重复)
|
||||||
return props.getPopupContainer(node);
|
const newRecords = records.filter(record =>
|
||||||
} else {
|
!allAreas.value.some(Area => Area.id === record.id)
|
||||||
return node?.parentNode;
|
);
|
||||||
|
allAreas.value = [...allAreas.value, ...newRecords];
|
||||||
|
Options.value = [...Options.value, ...newRecords];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修正分页判断逻辑
|
||||||
|
isHasData.value = records.length >= props.pageSize;
|
||||||
|
|
||||||
|
emit('optionsLoaded', allAreas.value);
|
||||||
|
} catch (error) {
|
||||||
|
if (page === 1) {
|
||||||
|
allAreas.value = [];
|
||||||
|
Options.value = [];
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
scrollLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function queryDataById(value: string) {
|
||||||
|
try {
|
||||||
|
const res = await queryById({ id: value });
|
||||||
|
if (res) {
|
||||||
|
// 将查询到的单个库区信息添加到列表中,确保唯一性
|
||||||
|
const Area = Array.isArray(res) ? res[0] : res;
|
||||||
|
if (Area) {
|
||||||
|
// 使用ensureUnique确保库区不重复
|
||||||
|
allAreas.value = ensureUnique(allAreas.value, Area);
|
||||||
|
Options.value = ensureUnique(Options.value, Area);
|
||||||
}
|
}
|
||||||
|
return Area;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('查询库区失败:', error);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据选项值找到对应的选项对象
|
||||||
|
*/
|
||||||
|
function findOptionByValue(value: string): Area | undefined {
|
||||||
|
if (props.returnValue === 'object' || props.returnValue === 'id') {
|
||||||
|
return allAreas.value.find((Area) => Area.id === value);
|
||||||
|
} else {
|
||||||
|
return allAreas.value.find((Area) => Area[props.returnValue as keyof Area] === value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取需要返回的值
|
||||||
|
*/
|
||||||
|
function getReturnValue(value: string | string[]) {
|
||||||
|
if (!value) {
|
||||||
|
return props.multiple ? [] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果返回整个对象
|
||||||
|
if (props.returnValue === 'object') {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((v) => findOptionByValue(v)).filter(Boolean);
|
||||||
|
} else {
|
||||||
|
return findOptionByValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 如果返回ID(默认情况)
|
||||||
/**
|
else if (props.returnValue === 'id') {
|
||||||
* 过滤选项 - 禁用前端过滤,使用后端搜索
|
return value;
|
||||||
*/
|
|
||||||
function filterOption(_input: string, _option: any) {
|
|
||||||
return true; // 禁用前端过滤,完全依赖后端搜索
|
|
||||||
}
|
}
|
||||||
|
// 如果返回对象中的某个字段
|
||||||
/**
|
else {
|
||||||
* 获取库区数据
|
if (Array.isArray(value)) {
|
||||||
*/
|
return value.map((v) => {
|
||||||
const fetchAreas = async (page = 1, keyword = '', isSearch = false) => {
|
const option = findOptionByValue(v);
|
||||||
try {
|
return option ? option[props.returnValue as keyof Area] : v;
|
||||||
loading.value = true;
|
|
||||||
|
|
||||||
const res = await defHttp.get<ResponseData>({
|
|
||||||
url: '/base/area/list',
|
|
||||||
params: {
|
|
||||||
pageSize: props.pageSize,
|
|
||||||
pageNo: page,
|
|
||||||
keyword: keyword,
|
|
||||||
izActive: props.izActive,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('获取库区数据成功:', res);
|
|
||||||
const records = res.records || [];
|
|
||||||
|
|
||||||
if (page === 1 || isSearch) {
|
|
||||||
// 第一页或搜索时,重置数据
|
|
||||||
allAreas.value = records;
|
|
||||||
areaOptions.value = records;
|
|
||||||
} else {
|
|
||||||
// 滚动加载时,追加数据
|
|
||||||
allAreas.value = [...allAreas.value, ...records];
|
|
||||||
areaOptions.value = [...areaOptions.value, ...records];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修正分页判断逻辑
|
|
||||||
isHasData.value = records.length >= props.pageSize;
|
|
||||||
console.log('是否还有更多数据:', records.length);
|
|
||||||
|
|
||||||
emit('optionsLoaded', allAreas.value);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取库区数据失败:', error);
|
|
||||||
if (page === 1) {
|
|
||||||
allAreas.value = [];
|
|
||||||
areaOptions.value = [];
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
scrollLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据选项值找到对应的选项对象
|
|
||||||
*/
|
|
||||||
function findOptionByValue(value: string): Area | undefined {
|
|
||||||
if (props.returnValue === 'object' || props.returnValue === 'id') {
|
|
||||||
return allAreas.value.find((item) => item.id === value);
|
|
||||||
} else {
|
} else {
|
||||||
return allAreas.value.find((item) => item[props.returnValue as keyof Area] === value);
|
const option = findOptionByValue(value);
|
||||||
|
return option ? option[props.returnValue as keyof Area] : value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取需要返回的值
|
* 搜索处理(防抖)
|
||||||
*/
|
*/
|
||||||
function getReturnValue(value: string | string[]) {
|
const handleSearch = debounce(function (value: string) {
|
||||||
if (!value) {
|
searchKeyword.value = value;
|
||||||
return props.multiple ? [] : undefined;
|
pageNo.value = 1;
|
||||||
}
|
isHasData.value = true;
|
||||||
|
|
||||||
// 如果返回整个对象
|
// 直接调用API进行搜索
|
||||||
if (props.returnValue === 'object') {
|
queryData(1, value, true);
|
||||||
if (Array.isArray(value)) {
|
}, 300);
|
||||||
return value.map((v) => findOptionByValue(v)).filter(Boolean);
|
|
||||||
} else {
|
|
||||||
return findOptionByValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 如果返回ID(默认情况)
|
|
||||||
else if (props.returnValue === 'id') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
// 如果返回对象中的某个字段
|
|
||||||
else {
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
return value.map((v) => {
|
|
||||||
const option = findOptionByValue(v);
|
|
||||||
return option ? option[props.returnValue as keyof Area] : v;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const option = findOptionByValue(value);
|
|
||||||
return option ? option[props.returnValue as keyof Area] : value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索处理(防抖)
|
* 处理焦点事件
|
||||||
*/
|
*/
|
||||||
const handleSearch = debounce(function (value: string) {
|
function handleFocus() {
|
||||||
searchKeyword.value = value;
|
// 如果还没有数据,加载数据
|
||||||
|
if (allAreas.value.length === 0 && props.async) {
|
||||||
pageNo.value = 1;
|
pageNo.value = 1;
|
||||||
isHasData.value = true;
|
isHasData.value = true;
|
||||||
|
queryData(1, '');
|
||||||
|
}
|
||||||
|
attrs.onFocus?.();
|
||||||
|
}
|
||||||
|
|
||||||
// 直接调用API进行搜索
|
/**
|
||||||
fetchAreas(1, value, true);
|
* 处理值变化
|
||||||
}, 300);
|
*/
|
||||||
|
function handleChange(value: string | string[]) {
|
||||||
|
selectedValue.value = value;
|
||||||
|
|
||||||
/**
|
// 根据配置返回相应的值
|
||||||
* 处理焦点事件
|
const returnValue = getReturnValue(value);
|
||||||
*/
|
emit('update:value', returnValue);
|
||||||
function handleFocus() {
|
emit('change', returnValue);
|
||||||
// 如果还没有数据,加载数据
|
}
|
||||||
if (allAreas.value.length === 0 && props.async) {
|
|
||||||
pageNo.value = 1;
|
/**
|
||||||
isHasData.value = true;
|
* 滚动加载处理
|
||||||
fetchAreas(1, '');
|
*/
|
||||||
}
|
function handlePopupScroll(e: Event) {
|
||||||
attrs.onFocus?.();
|
const target = e.target as HTMLElement;
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = target;
|
||||||
|
|
||||||
|
if (!scrollLoading.value && isHasData.value && scrollTop + clientHeight >= scrollHeight - 10) {
|
||||||
|
scrollLoading.value = true;
|
||||||
|
pageNo.value++;
|
||||||
|
|
||||||
|
queryData(pageNo.value, searchKeyword.value)
|
||||||
|
.finally(() => {
|
||||||
|
scrollLoading.value = false;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
pageNo.value--;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据选中值初始化显示文本
|
||||||
|
*/
|
||||||
|
const initSelectValue = async () => {
|
||||||
|
if (!props.value) {
|
||||||
|
selectedValue.value = props.multiple ? [] : undefined;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 如果是异步模式且还没有加载数据,则先加载数据
|
||||||
* 处理值变化
|
if (props.async && allAreas.value.length === 0) {
|
||||||
*/
|
await queryData();
|
||||||
function handleChange(value: string | string[]) {
|
|
||||||
selectedValue.value = value;
|
|
||||||
|
|
||||||
// 根据配置返回相应的值
|
|
||||||
const returnValue = getReturnValue(value);
|
|
||||||
console.log('值变化:', returnValue);
|
|
||||||
emit('update:value', returnValue);
|
|
||||||
emit('change', returnValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 根据不同的returnValue设置选中的值
|
||||||
* 滚动加载处理
|
let valueIds: string[] = [];
|
||||||
*/
|
|
||||||
function handlePopupScroll(e: Event) {
|
|
||||||
const target = e.target as HTMLElement;
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = target;
|
|
||||||
|
|
||||||
if (!scrollLoading.value && isHasData.value && scrollTop + clientHeight >= scrollHeight - 10) {
|
if (props.returnValue === 'object') {
|
||||||
console.log('滚动加载更多');
|
// 如果返回的是对象,value可能是对象或对象数组
|
||||||
scrollLoading.value = true;
|
if (Array.isArray(props.value)) {
|
||||||
pageNo.value++;
|
valueIds = props.value.map((Area: any) => Area.id);
|
||||||
|
selectedValue.value = valueIds;
|
||||||
fetchAreas(pageNo.value, searchKeyword.value)
|
|
||||||
.finally(() => {
|
|
||||||
scrollLoading.value = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
pageNo.value--;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据选中值初始化显示文本
|
|
||||||
*/
|
|
||||||
const initSelectValue = async () => {
|
|
||||||
if (!props.value) {
|
|
||||||
selectedValue.value = props.multiple ? [] : undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是异步模式且还没有加载数据,则先加载数据
|
|
||||||
if (props.async && allAreas.value.length === 0) {
|
|
||||||
await fetchAreas();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据不同的returnValue设置选中的值
|
|
||||||
if (props.returnValue === 'object') {
|
|
||||||
// 如果返回的是对象,value可能是对象或对象数组
|
|
||||||
if (Array.isArray(props.value)) {
|
|
||||||
selectedValue.value = props.value.map((item: any) => item.id);
|
|
||||||
} else {
|
|
||||||
selectedValue.value = (props.value as any).id;
|
|
||||||
}
|
|
||||||
} else if (props.returnValue === 'id') {
|
|
||||||
selectedValue.value = props.value as string | string[];
|
|
||||||
} else {
|
} else {
|
||||||
// 对于其他字段类型,直接使用传入的值
|
valueIds = [(props.value as any).id];
|
||||||
selectedValue.value = props.value as string | string[];
|
selectedValue.value = valueIds[0];
|
||||||
}
|
}
|
||||||
};
|
} else if (props.returnValue === 'id') {
|
||||||
|
if (Array.isArray(props.value)) {
|
||||||
// 监听value变化
|
valueIds = props.value as string[];
|
||||||
watch(
|
selectedValue.value = valueIds;
|
||||||
() => props.value,
|
} else {
|
||||||
() => {
|
valueIds = [props.value as string];
|
||||||
initSelectValue();
|
selectedValue.value = valueIds[0];
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
// 组件挂载时初始化
|
|
||||||
onMounted(() => {
|
|
||||||
if (!props.async) {
|
|
||||||
fetchAreas();
|
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
// 对于其他字段类型,直接使用传入的值
|
||||||
|
selectedValue.value = props.value as string | string[];
|
||||||
|
// 这里需要根据字段值查找对应的ID
|
||||||
|
if (Array.isArray(props.value)) {
|
||||||
|
valueIds = props.value.map((v) => {
|
||||||
|
const option = allAreas.value.find((Area) => Area[props.returnValue as keyof Area] === v);
|
||||||
|
return option ? option.id : v;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const option = allAreas.value.find((Area) => Area[props.returnValue as keyof Area] === props.value);
|
||||||
|
valueIds = option ? [option.id] : [props.value as string];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
// 检查是否有值不在当前列表中,如果有则查询
|
||||||
attrs,
|
const missingIds = valueIds.filter((id) => !allAreas.value.some((Area) => Area.id === id));
|
||||||
areaOptions,
|
if (missingIds.length > 0) {
|
||||||
loading,
|
// 对每个不在列表中的ID进行查询
|
||||||
selectedValue,
|
const queryPromises = missingIds.map((id) => queryDataById(id));
|
||||||
notFoundContent,
|
await Promise.all(queryPromises);
|
||||||
getParentContainer,
|
}
|
||||||
filterOption,
|
};
|
||||||
handleChange,
|
|
||||||
handleSearch,
|
// 监听value变化
|
||||||
handleFocus,
|
watch(
|
||||||
getOptionLabel,
|
() => props.value,
|
||||||
getOptionValue,
|
() => {
|
||||||
handlePopupScroll,
|
initSelectValue();
|
||||||
};
|
},
|
||||||
},
|
{ immediate: true }
|
||||||
});
|
);
|
||||||
|
|
||||||
|
// 组件挂载时初始化
|
||||||
|
onMounted(() => {
|
||||||
|
if (!props.async) {
|
||||||
|
queryData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
attrs,
|
||||||
|
Options,
|
||||||
|
loading,
|
||||||
|
selectedValue,
|
||||||
|
notFoundContent,
|
||||||
|
getParentContainer,
|
||||||
|
filterOption,
|
||||||
|
handleChange,
|
||||||
|
handleSearch,
|
||||||
|
handleFocus,
|
||||||
|
getOptionLabel,
|
||||||
|
getOptionValue,
|
||||||
|
handlePopupScroll,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@
|
||||||
v-bind="attrs"
|
v-bind="attrs"
|
||||||
>
|
>
|
||||||
<template #notFoundContent>
|
<template #notFoundContent>
|
||||||
<a-spin v-if="loading" size="small" />
|
|
||||||
<span v-else>暂无物料数据</span>
|
|
||||||
</template>
|
</template>
|
||||||
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
||||||
{{ getOptionLabel(option) }}
|
{{ getOptionLabel(option) }}
|
||||||
|
|
@ -78,6 +77,8 @@
|
||||||
returnValue: propTypes.string.def('id'),
|
returnValue: propTypes.string.def('id'),
|
||||||
//默认启用
|
//默认启用
|
||||||
izActive: propTypes.number.def(1),
|
izActive: propTypes.number.def(1),
|
||||||
|
//默认未删除
|
||||||
|
delFlag: propTypes.number.def(0),
|
||||||
},
|
},
|
||||||
emits: ['change', 'update:value', 'optionsLoaded'],
|
emits: ['change', 'update:value', 'optionsLoaded'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
|
@ -97,7 +98,7 @@
|
||||||
|
|
||||||
// 未找到内容
|
// 未找到内容
|
||||||
const notFoundContent = computed(() => {
|
const notFoundContent = computed(() => {
|
||||||
return loading.value ? undefined : null;
|
return loading.value ? undefined : '暂无数据';
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -165,6 +166,7 @@
|
||||||
pageNo: page,
|
pageNo: page,
|
||||||
keyword: keyword,
|
keyword: keyword,
|
||||||
izActive: props.izActive,
|
izActive: props.izActive,
|
||||||
|
delFlag: props.delFlag,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@
|
||||||
:getPopupContainer="getParentContainer"
|
:getPopupContainer="getParentContainer"
|
||||||
v-bind="attrs"
|
v-bind="attrs"
|
||||||
>
|
>
|
||||||
<template #notFoundContent>
|
<template #notFoundContent></template>
|
||||||
<a-spin v-if="loading" size="small" />
|
|
||||||
<span v-else>暂无库位数据</span>
|
|
||||||
</template>
|
|
||||||
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
||||||
{{ getOptionLabel(option) }}
|
{{ getOptionLabel(option) }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
|
|
@ -76,8 +73,14 @@
|
||||||
immediateChange: propTypes.bool.def(false),
|
immediateChange: propTypes.bool.def(false),
|
||||||
// 返回值类型: 'id'(默认) | 'object' | 其他字段名
|
// 返回值类型: 'id'(默认) | 'object' | 其他字段名
|
||||||
returnValue: propTypes.string.def('id'),
|
returnValue: propTypes.string.def('id'),
|
||||||
|
//默认空闲
|
||||||
|
status: propTypes.number.def(0),
|
||||||
//默认启用
|
//默认启用
|
||||||
izActive: propTypes.number.def(1),
|
izActive: propTypes.number.def(1),
|
||||||
|
//默认未删除
|
||||||
|
delFlag: propTypes.number.def(0),
|
||||||
|
//库区ID
|
||||||
|
areaCode: propTypes.array,
|
||||||
},
|
},
|
||||||
emits: ['change', 'update:value', 'optionsLoaded'],
|
emits: ['change', 'update:value', 'optionsLoaded'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
|
@ -97,7 +100,7 @@
|
||||||
|
|
||||||
// 未找到内容
|
// 未找到内容
|
||||||
const notFoundContent = computed(() => {
|
const notFoundContent = computed(() => {
|
||||||
return loading.value ? undefined : null;
|
return loading.value ? undefined : '暂无数据';
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,7 +150,7 @@
|
||||||
*/
|
*/
|
||||||
function ensureUnique(Points: Point[], newPoint: Point): Point[] {
|
function ensureUnique(Points: Point[], newPoint: Point): Point[] {
|
||||||
// 如果已经存在相同id的库位,先移除旧的再添加新的
|
// 如果已经存在相同id的库位,先移除旧的再添加新的
|
||||||
const filtered = Points.filter(Point => Point.id !== newPoint.id);
|
const filtered = Points.filter((Point) => Point.id !== newPoint.id);
|
||||||
return [newPoint, ...filtered];
|
return [newPoint, ...filtered];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +167,10 @@
|
||||||
pageSize: props.pageSize,
|
pageSize: props.pageSize,
|
||||||
pageNo: page,
|
pageNo: page,
|
||||||
keyword: keyword,
|
keyword: keyword,
|
||||||
|
status: props.status,
|
||||||
izActive: props.izActive,
|
izActive: props.izActive,
|
||||||
|
delFlag: props.delFlag,
|
||||||
|
areaCode: props.areaCode,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -176,9 +182,7 @@
|
||||||
Options.value = records;
|
Options.value = records;
|
||||||
} else {
|
} else {
|
||||||
// 滚动加载时,追加数据(确保不重复)
|
// 滚动加载时,追加数据(确保不重复)
|
||||||
const newRecords = records.filter(record =>
|
const newRecords = records.filter((record) => !allPoints.value.some((Point) => Point.id === record.id));
|
||||||
!allPoints.value.some(Point => Point.id === record.id)
|
|
||||||
);
|
|
||||||
allPoints.value = [...allPoints.value, ...newRecords];
|
allPoints.value = [...allPoints.value, ...newRecords];
|
||||||
Options.value = [...Options.value, ...newRecords];
|
Options.value = [...Options.value, ...newRecords];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,6 @@ export const columns: BasicColumn[] = [
|
||||||
return render.renderTag(text, color);
|
return render.renderTag(text, color);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: '库位',
|
|
||||||
align: "center",
|
|
||||||
dataIndex: 'pointId_dictText'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: '是否启用',
|
title: '是否启用',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,6 @@
|
||||||
<JInput v-model:value="queryParam.stockCode" :placeholder="'请输入容器编码'" :type="JInputTypeEnum.JINPUT_RIGHT_LIKE" />
|
<JInput v-model:value="queryParam.stockCode" :placeholder="'请输入容器编码'" :type="JInputTypeEnum.JINPUT_RIGHT_LIKE" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="6">
|
|
||||||
<a-form-item name="pointId">
|
|
||||||
<template #label><span title="库位">库位</span></template>
|
|
||||||
<PointSelect v-model:value="queryParam.pointId" placeholder="请选择库位" />
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :lg="6">
|
<a-col :lg="6">
|
||||||
<a-form-item name="status">
|
<a-form-item name="status">
|
||||||
<template #label><span title="状态">状态</span></template>
|
<template #label><span title="状态">状态</span></template>
|
||||||
|
|
@ -88,21 +82,16 @@
|
||||||
import { list, deleteOne, batchDelete, saveOrUpdate, getImportUrl, getExportUrl } from './Stock.api';
|
import { list, deleteOne, batchDelete, saveOrUpdate, getImportUrl, getExportUrl } from './Stock.api';
|
||||||
import StockModal from './components/StockModal.vue';
|
import StockModal from './components/StockModal.vue';
|
||||||
import SwitchStatus from '/@/views/base/SwitchStatus.vue';
|
import SwitchStatus from '/@/views/base/SwitchStatus.vue';
|
||||||
import { useUserStore } from '/@/store/modules/user';
|
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
|
||||||
import { getDateByPicker } from '/@/utils';
|
import { getDateByPicker } from '/@/utils';
|
||||||
import { JDictSelectTag, JSearchSelect } from '@/components/Form';
|
import { JDictSelectTag, JSearchSelect } from '@/components/Form';
|
||||||
import { JInputTypeEnum } from '@/enums/cpteEnum';
|
import { JInputTypeEnum } from '@/enums/cpteEnum';
|
||||||
import JInput from '../../../components/Form/src/jeecg/components/JInput.vue';
|
import JInput from '../../../components/Form/src/jeecg/components/JInput.vue';
|
||||||
import PointSelect from '@/views/base/point/components/PointSelect.vue';
|
|
||||||
const fieldPickers = reactive({});
|
const fieldPickers = reactive({});
|
||||||
|
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const queryParam = reactive<any>({});
|
const queryParam = reactive<any>({});
|
||||||
const toggleSearchStatus = ref<boolean>(false);
|
const toggleSearchStatus = ref<boolean>(false);
|
||||||
const registerModal = ref();
|
const registerModal = ref();
|
||||||
const userStore = useUserStore();
|
|
||||||
const { createMessage } = useMessage();
|
|
||||||
|
|
||||||
//将是否启用转换成开关
|
//将是否启用转换成开关
|
||||||
const enhancedColumns = columns.map((col) => {
|
const enhancedColumns = columns.map((col) => {
|
||||||
|
|
@ -130,7 +119,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
//注册table数据
|
//注册table数据
|
||||||
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
|
const { tableContext, onExportXls, onImportXls } = useListPage({
|
||||||
tableProps: {
|
tableProps: {
|
||||||
title: '容器',
|
title: '容器',
|
||||||
api: list,
|
api: list,
|
||||||
|
|
@ -164,7 +153,7 @@
|
||||||
success: handleSuccess,
|
success: handleSuccess,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] =
|
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] =
|
||||||
tableContext;
|
tableContext;
|
||||||
const labelCol = reactive({
|
const labelCol = reactive({
|
||||||
xs: 24,
|
xs: 24,
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,6 @@
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24">
|
|
||||||
<a-form-item label="库位" v-bind="validateInfos.pointId" id="StockForm-pointId" name="pointId">
|
|
||||||
<PointSelect v-model:value="formData.pointId" />
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
<a-form-item label="描述" v-bind="validateInfos.description" id="StockForm-description" name="description">
|
<a-form-item label="描述" v-bind="validateInfos.description" id="StockForm-description" name="description">
|
||||||
<a-textarea v-model:value="formData.description" :rows="4" placeholder="请输入描述" />
|
<a-textarea v-model:value="formData.description" :rows="4" placeholder="请输入描述" />
|
||||||
|
|
@ -57,7 +52,6 @@
|
||||||
import JSwitch from '@/components/Form/src/jeecg/components/JSwitch.vue';
|
import JSwitch from '@/components/Form/src/jeecg/components/JSwitch.vue';
|
||||||
import { JDictSelectTag } from '@/components/Form';
|
import { JDictSelectTag } from '@/components/Form';
|
||||||
import { getTenantId } from '@/utils/auth';
|
import { getTenantId } from '@/utils/auth';
|
||||||
import PointSelect from '@/views/base/point/components/PointSelect.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
formDisabled: { type: Boolean, default: false },
|
formDisabled: { type: Boolean, default: false },
|
||||||
|
|
@ -71,7 +65,6 @@
|
||||||
let tenantId = getTenantId();
|
let tenantId = getTenantId();
|
||||||
const formData = reactive<Record<string, any>>({
|
const formData = reactive<Record<string, any>>({
|
||||||
id: '',
|
id: '',
|
||||||
pointId: '',
|
|
||||||
stockCode: '',
|
stockCode: '',
|
||||||
stockType: 'TRAY',
|
stockType: 'TRAY',
|
||||||
status: 0,
|
status: 0,
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@
|
||||||
v-bind="attrs"
|
v-bind="attrs"
|
||||||
>
|
>
|
||||||
<template #notFoundContent>
|
<template #notFoundContent>
|
||||||
<a-spin v-if="loading" size="small" />
|
|
||||||
<span v-else>暂无容器数据</span>
|
|
||||||
</template>
|
</template>
|
||||||
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
<a-select-option v-for="option in Options" :key="option.id" :value="getOptionValue(option)">
|
||||||
{{ getOptionLabel(option) }}
|
{{ getOptionLabel(option) }}
|
||||||
|
|
@ -75,8 +74,14 @@
|
||||||
immediateChange: propTypes.bool.def(false),
|
immediateChange: propTypes.bool.def(false),
|
||||||
// 返回值类型: 'id'(默认) | 'object' | 其他字段名
|
// 返回值类型: 'id'(默认) | 'object' | 其他字段名
|
||||||
returnValue: propTypes.string.def('id'),
|
returnValue: propTypes.string.def('id'),
|
||||||
|
//默认空闲
|
||||||
|
status: propTypes.number.def(0),
|
||||||
//默认启用
|
//默认启用
|
||||||
izActive: propTypes.number.def(1),
|
izActive: propTypes.number.def(1),
|
||||||
|
//默认未删除
|
||||||
|
delFlag: propTypes.number.def(0),
|
||||||
|
//是否扫描
|
||||||
|
izScan: propTypes.bool.def(false),
|
||||||
},
|
},
|
||||||
emits: ['change', 'update:value', 'optionsLoaded'],
|
emits: ['change', 'update:value', 'optionsLoaded'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
|
@ -96,7 +101,7 @@
|
||||||
|
|
||||||
// 未找到内容
|
// 未找到内容
|
||||||
const notFoundContent = computed(() => {
|
const notFoundContent = computed(() => {
|
||||||
return loading.value ? undefined : null;
|
return loading.value ? undefined : '暂无数据';
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -146,7 +151,7 @@
|
||||||
*/
|
*/
|
||||||
function ensureUnique(Stocks: Stock[], newStock: Stock): Stock[] {
|
function ensureUnique(Stocks: Stock[], newStock: Stock): Stock[] {
|
||||||
// 如果已经存在相同id的容器,先移除旧的再添加新的
|
// 如果已经存在相同id的容器,先移除旧的再添加新的
|
||||||
const filtered = Stocks.filter(Stock => Stock.id !== newStock.id);
|
const filtered = Stocks.filter((Stock) => Stock.id !== newStock.id);
|
||||||
return [newStock, ...filtered];
|
return [newStock, ...filtered];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,11 +168,15 @@
|
||||||
pageSize: props.pageSize,
|
pageSize: props.pageSize,
|
||||||
pageNo: page,
|
pageNo: page,
|
||||||
keyword: keyword,
|
keyword: keyword,
|
||||||
|
status: props.status,
|
||||||
izActive: props.izActive,
|
izActive: props.izActive,
|
||||||
|
delFlag: props.delFlag,
|
||||||
|
izScan: props.izScan,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const records = res.records || [];
|
const records = res.records || [];
|
||||||
|
console.log('res', records)
|
||||||
|
|
||||||
if (page === 1 || isSearch) {
|
if (page === 1 || isSearch) {
|
||||||
// 第一页或搜索时,重置数据
|
// 第一页或搜索时,重置数据
|
||||||
|
|
@ -175,9 +184,7 @@
|
||||||
Options.value = records;
|
Options.value = records;
|
||||||
} else {
|
} else {
|
||||||
// 滚动加载时,追加数据(确保不重复)
|
// 滚动加载时,追加数据(确保不重复)
|
||||||
const newRecords = records.filter(record =>
|
const newRecords = records.filter((record) => !allStocks.value.some((Stock) => Stock.id === record.id));
|
||||||
!allStocks.value.some(Stock => Stock.id === record.id)
|
|
||||||
);
|
|
||||||
allStocks.value = [...allStocks.value, ...newRecords];
|
allStocks.value = [...allStocks.value, ...newRecords];
|
||||||
Options.value = [...Options.value, ...newRecords];
|
Options.value = [...Options.value, ...newRecords];
|
||||||
}
|
}
|
||||||
|
|
@ -296,6 +303,7 @@
|
||||||
const returnValue = getReturnValue(value);
|
const returnValue = getReturnValue(value);
|
||||||
emit('update:value', returnValue);
|
emit('update:value', returnValue);
|
||||||
emit('change', returnValue);
|
emit('change', returnValue);
|
||||||
|
console.log('值变化:', returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<a-col :lg="6">
|
<a-col :lg="6">
|
||||||
<a-form-item name="pointId">
|
<a-form-item name="pointId">
|
||||||
<template #label><span title="库位">库位</span></template>
|
<template #label><span title="库位">库位</span></template>
|
||||||
<PointSelect v-model:value="queryParam.pointId" />
|
<PointSelect v-model:value="queryParam.pointId" :area-code="['CPCCQ', 'MJCCQ']" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="6">
|
<a-col :lg="6">
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,12 @@ export const columns: BasicColumn[] = [
|
||||||
dataIndex: 'logType_dictText',
|
dataIndex: 'logType_dictText',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '业务单号',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'businessNo',
|
||||||
|
width: 130,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '物料',
|
title: '物料',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
|
@ -17,19 +23,19 @@ export const columns: BasicColumn[] = [
|
||||||
title: '原库位',
|
title: '原库位',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
dataIndex: 'fromPointId_dictText',
|
dataIndex: 'fromPointId_dictText',
|
||||||
width: 120,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '目标库位',
|
title: '目标库位',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
dataIndex: 'toPointId_dictText',
|
dataIndex: 'toPointId_dictText',
|
||||||
width: 120,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '容器',
|
title: '容器',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
dataIndex: 'stockId_dictText',
|
dataIndex: 'stockId_dictText',
|
||||||
width: 120,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '变动前数量',
|
title: '变动前数量',
|
||||||
|
|
@ -50,15 +56,36 @@ export const columns: BasicColumn[] = [
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '变动前分配数量',
|
title: '分配前数量',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
dataIndex: 'beforeAllocatedQty',
|
dataIndex: 'beforeAllocatedQty',
|
||||||
width: 120,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '变动后分配数量',
|
title: '分配数量',
|
||||||
|
align: 'center',
|
||||||
|
dataIndex: 'allocatedQty',
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ record }) => {
|
||||||
|
// 从记录中获取分配前和分配后的数量
|
||||||
|
const before = record.beforeAllocatedQty || 0;
|
||||||
|
const after = record.afterAllocatedQty || 0;
|
||||||
|
if(record.logType_dictText==='分配'){
|
||||||
|
if(before>0){
|
||||||
|
return after - before;
|
||||||
|
}
|
||||||
|
return before + after;
|
||||||
|
}else if(record.logType_dictText==='取消分配'){
|
||||||
|
return before - after;
|
||||||
|
}else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分配后数量',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
dataIndex: 'afterAllocatedQty',
|
dataIndex: 'afterAllocatedQty',
|
||||||
width: 120,
|
width: 100,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,7 @@
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
<a-form-item label="托盘" v-bind="validateInfos.stockCode" id="ScanTrayForm-stockCode" name="stockCode">
|
<a-form-item label="托盘" v-bind="validateInfos.stockCode" id="ScanTrayForm-stockCode" name="stockCode">
|
||||||
<JSearchSelect
|
<StockSelect v-model:value="formData.stockCode" :return-value="'stockCode'" :status="1" :iz-scan="true" />
|
||||||
v-model:value="formData.stockCode"
|
|
||||||
placeholder="请选择托盘"
|
|
||||||
dict="base_stock where status=1 and iz_active=1 and del_flag=0,stock_code,stock_code"
|
|
||||||
allowClear
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
|
|
@ -38,6 +33,7 @@
|
||||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||||
import { JSearchSelect } from '@/components/Form';
|
import { JSearchSelect } from '@/components/Form';
|
||||||
import { scanTray } from '@/views/conveyorLine/ConveyorLine.api';
|
import { scanTray } from '@/views/conveyorLine/ConveyorLine.api';
|
||||||
|
import StockSelect from '@/views/base/stock/components/StockSelect.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
formDisabled: { type: Boolean, default: false },
|
formDisabled: { type: Boolean, default: false },
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ enum Api {
|
||||||
queryTaskByMainId = '/shipping/pick/queryTaskByMainId',
|
queryTaskByMainId = '/shipping/pick/queryTaskByMainId',
|
||||||
allocatePick = '/shipping/pick/allocatePick',
|
allocatePick = '/shipping/pick/allocatePick',
|
||||||
cancelAllocate = '/shipping/pick/cancelAllocate',
|
cancelAllocate = '/shipping/pick/cancelAllocate',
|
||||||
|
pickTask = '/shipping/pick/pickTask',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -123,3 +124,13 @@ export const cancelAllocate = (ids,handleSuccess) => {
|
||||||
handleSuccess();
|
handleSuccess();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出库单拣货
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const pickTask = (ids,handleSuccess) => {
|
||||||
|
return defHttp.get({ url: Api.pickTask, params: { ids } }, { joinParamsToUrl: true }).then(() => {
|
||||||
|
handleSuccess();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@
|
||||||
</a-row>
|
</a-row>
|
||||||
<a-row :gutter="24">
|
<a-row :gutter="24">
|
||||||
<a-col :lg="6">
|
<a-col :lg="6">
|
||||||
<a-form-item name="status">
|
<a-form-item name="status_MultiString">
|
||||||
<template #label><span title="状态">状态</span></template>
|
<template #label><span title="状态">状态</span></template>
|
||||||
<JDictSelectTag v-model:value="queryParam.status" placeholder="请选择" dictCode="pick_status" mode="multiple" allowClear />
|
<JSelectMultiple v-model:value="queryParam.status_MultiString" dictCode="pick_status" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
@ -53,22 +53,34 @@
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:loading="allocate_loading"
|
:loading="allocate_loading"
|
||||||
|
:disabled="selectedRowKeys.length === 0"
|
||||||
v-auth="'shipping:data_pick:allocatePick'"
|
v-auth="'shipping:data_pick:allocatePick'"
|
||||||
@click="handleAllocatePick"
|
@click="handleAllocatePick"
|
||||||
preIcon="ant-design:edit-outlined"
|
preIcon="ant-design:edit-outlined"
|
||||||
>
|
>
|
||||||
分配
|
批量分配
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
danger
|
danger
|
||||||
:loading="cancel_loading"
|
:loading="cancel_loading"
|
||||||
|
:disabled="selectedRowKeys.length === 0"
|
||||||
v-auth="'shipping:data_pick:cancelAllocate'"
|
v-auth="'shipping:data_pick:cancelAllocate'"
|
||||||
@click="handleCancelAllocate"
|
@click="handleCancelAllocate"
|
||||||
preIcon="ant-design:edit-outlined"
|
preIcon="ant-design:edit-outlined"
|
||||||
>
|
>
|
||||||
取消分配
|
取消分配
|
||||||
</a-button>
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
:loading="pick_loading"
|
||||||
|
:disabled="selectedRowKeys.length === 0"
|
||||||
|
v-auth="'shipping:data_pick:pickTask'"
|
||||||
|
@click="handlePick"
|
||||||
|
preIcon="ant-design:edit-outlined"
|
||||||
|
>
|
||||||
|
批量拣货
|
||||||
|
</a-button>
|
||||||
<a-button type="primary" v-auth="'shipping:data_pick:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出 </a-button>
|
<a-button type="primary" v-auth="'shipping:data_pick:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出 </a-button>
|
||||||
<j-upload-button type="primary" v-auth="'shipping:data_pick:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls"
|
<j-upload-button type="primary" v-auth="'shipping:data_pick:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls"
|
||||||
>导入
|
>导入
|
||||||
|
|
@ -107,15 +119,17 @@
|
||||||
import { useModal } from '/@/components/Modal';
|
import { useModal } from '/@/components/Modal';
|
||||||
import PickModal from './components/PickModal.vue';
|
import PickModal from './components/PickModal.vue';
|
||||||
import { columns } from './Pick.data';
|
import { columns } from './Pick.data';
|
||||||
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, allocatePick, cancelAllocate } from './Pick.api';
|
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, allocatePick, cancelAllocate, pickTask } from './Pick.api';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import { getDateByPicker } from '/@/utils';
|
import { getDateByPicker } from '/@/utils';
|
||||||
import { JInputTypeEnum } from '@/enums/cpteEnum';
|
import { JInputTypeEnum } from '@/enums/cpteEnum';
|
||||||
import { JInput, JDictSelectTag } from '@/components/Form';
|
import { JInput, JDictSelectTag } from '@/components/Form';
|
||||||
import JRangeDate from '@/components/Form/src/jeecg/components/JRangeDate.vue';
|
import JRangeDate from '@/components/Form/src/jeecg/components/JRangeDate.vue';
|
||||||
|
import JSelectMultiple from '/@/components/Form/src/jeecg/components/JSelectMultiple.vue';
|
||||||
|
|
||||||
const allocate_loading = ref(false);
|
const allocate_loading = ref(false);
|
||||||
const cancel_loading = ref(false);
|
const cancel_loading = ref(false);
|
||||||
|
const pick_loading = ref(false);
|
||||||
const fieldPickers = reactive({});
|
const fieldPickers = reactive({});
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const queryParam = reactive<any>({});
|
const queryParam = reactive<any>({});
|
||||||
|
|
@ -184,10 +198,6 @@
|
||||||
* 分配事件
|
* 分配事件
|
||||||
*/
|
*/
|
||||||
async function handleAllocatePick() {
|
async function handleAllocatePick() {
|
||||||
if (selectedRowKeys.value.length === 0) {
|
|
||||||
return createMessage.error('请选择出库单');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选中的数据中状态有1、2、4 返回true,否则返回false
|
// 选中的数据中状态有1、2、4 返回true,否则返回false
|
||||||
const validStatuses = [1, 2, 4];
|
const validStatuses = [1, 2, 4];
|
||||||
const allValidStatus = selectedRows.value.every((row: any) => validStatuses.includes(row.status));
|
const allValidStatus = selectedRows.value.every((row: any) => validStatuses.includes(row.status));
|
||||||
|
|
@ -214,10 +224,6 @@
|
||||||
* 取消分配
|
* 取消分配
|
||||||
*/
|
*/
|
||||||
async function handleCancelAllocate() {
|
async function handleCancelAllocate() {
|
||||||
if (selectedRowKeys.value.length === 0) {
|
|
||||||
return createMessage.error('请选择出库单');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选中的数据中状态有2、3 返回true,否则返回false
|
// 选中的数据中状态有2、3 返回true,否则返回false
|
||||||
const validStatuses = [2, 3];
|
const validStatuses = [2, 3];
|
||||||
const allValidStatus = selectedRows.value.every((row: any) => validStatuses.includes(row.status));
|
const allValidStatus = selectedRows.value.every((row: any) => validStatuses.includes(row.status));
|
||||||
|
|
@ -240,6 +246,32 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拣货事件
|
||||||
|
*/
|
||||||
|
async function handlePick() {
|
||||||
|
// 选中的数据中状态有1、2、4 返回true,否则返回false
|
||||||
|
const validStatuses = [2, 3, 4];
|
||||||
|
const allValidStatus = selectedRows.value.every((row: any) => validStatuses.includes(row.status));
|
||||||
|
if (!allValidStatus) {
|
||||||
|
return createMessage.error('【部分分配、已分配、部分拣货】状态的出库单才允许拣货');
|
||||||
|
}
|
||||||
|
if (pick_loading.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 设置加载状态,防止重复提交
|
||||||
|
pick_loading.value = true;
|
||||||
|
try {
|
||||||
|
await pickTask(selectedRowKeys.value, handleSuccess);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('拣货失败:', e);
|
||||||
|
handleSuccess();
|
||||||
|
} finally {
|
||||||
|
// 重置加载状态
|
||||||
|
pick_loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑事件
|
* 编辑事件
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue