fix: 🧩 文章列表查询功能文章分类2级查询ID未传

This commit is contained in:
2025-09-19 17:59:00 +08:00
parent f7979b4e9b
commit f97dc8fd2e
5 changed files with 801 additions and 41 deletions

9
src/components.d.ts vendored
View File

@@ -7,16 +7,12 @@ export {}
declare module "vue" {
export interface GlobalComponents {
Css: typeof import("./components/SearchForm/components/css.vue")["default"];
ElAside: typeof import("element-plus/es")["ElAside"];
ElAutocomplete: typeof import("element-plus/es")["ElAutocomplete"];
ElBreadcrumb: typeof import("element-plus/es")["ElBreadcrumb"];
ElBreadcrumbItem: typeof import("element-plus/es")["ElBreadcrumbItem"];
ElButton: typeof import("element-plus/es")["ElButton"];
ElCarousel: typeof import("element-plus/es")["ElCarousel"];
ElCarouselItem: typeof import("element-plus/es")["ElCarouselItem"];
ElCheckbox: typeof import("element-plus/es")["ElCheckbox"];
ElCheckboxGroup: typeof import("element-plus/es")["ElCheckboxGroup"];
ElColorPicker: typeof import("element-plus/es")["ElColorPicker"];
ElContainer: typeof import("element-plus/es")["ElContainer"];
ElDatePicker: typeof import("element-plus/es")["ElDatePicker"];
ElDialog: typeof import("element-plus/es")["ElDialog"];
@@ -38,7 +34,6 @@ declare module "vue" {
ElOption: typeof import("element-plus/es")["ElOption"];
ElPagination: typeof import("element-plus/es")["ElPagination"];
ElRadio: typeof import("element-plus/es")["ElRadio"];
ElRadioButton: typeof import("element-plus/es")["ElRadioButton"];
ElRadioGroup: typeof import("element-plus/es")["ElRadioGroup"];
ElScrollbar: typeof import("element-plus/es")["ElScrollbar"];
ElSelect: typeof import("element-plus/es")["ElSelect"];
@@ -49,8 +44,6 @@ declare module "vue" {
ElTabPane: typeof import("element-plus/es")["ElTabPane"];
ElTabs: typeof import("element-plus/es")["ElTabs"];
ElTag: typeof import("element-plus/es")["ElTag"];
ElTooltip: typeof import("element-plus/es")["ElTooltip"];
ElTree: typeof import("element-plus/es")["ElTree"];
ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"];
ElUpload: typeof import("element-plus/es")["ElUpload"];
IEpArrowDown: typeof import("~icons/ep/arrow-down")["default"];

View File

@@ -77,9 +77,10 @@
:check-strictly="false"
show-checkbox
style="width: 224px"
clearable
:collapse-tags="true"
:collapse-tags="false"
ref="treeSelectRef"
@change="handleTreeSelectChange(item)"
@remove-tag="handleRemoveTag(item, $event)"
/>
</template>
<!-- 双 -->
@@ -158,12 +159,12 @@
<script lang="ts" setup name="SearchFormItem">
// import { verificationInput } from "./utils/verificationInput";
import { getCountryListApi } from "@/api/modules/global";
import $Bus from "@/utils/mittBus";
import { cloneDeep } from "lodash-es";
import { ref } from "vue";
// import { ref } from "vue";
const $router = useRouter();
const routeName: any = ref($router.currentRoute.value.name);
const treeSelectRef = ref<any>(null);
// const userStore: any = useUserStore();
interface SearchFormItem {
item: { [key: string]: any };
@@ -171,17 +172,8 @@ interface SearchFormItem {
search: (params: any) => void; // 搜索方法
handleEmitClear?: (item: any) => void;
}
let selectInputValue = ref(1);
const options = [
{
value: 1,
label: "序号"
},
{
value: 2,
label: "数字序列号"
}
];
// let selectInputValue = ref(1);
// const treeSelectValue = ref(null);
const props = defineProps<SearchFormItem>();
const _searchParam = computed(() => props.searchParam);
@@ -220,7 +212,119 @@ const remoteMethod = async (query: any, item: any) => {
}
loading.value = false;
};
// 关闭标签时同步 - 修复版
const handleRemoveTag = (item: any, removedValue: any) => {
nextTick(() => {
// 从item.options获取树形数据这是我们传递给组件的数据源
const allNodes = Array.isArray(item.options) ? item.options : [];
console.log(allNodes, "=allNodes=");
// 找到被删除的节点
const removedNode = findNode(allNodes, removedValue);
console.log(removedNode, "=removedNode=");
let ids: any = [];
if (removedNode) {
// 判断被删除的是父节点还是子节点
if (removedNode.children && Array.isArray(removedNode.children) && removedNode.children.length > 0) {
// 是父节点,需要删除所有子节点
const childIds = getAllChildIds(removedNode);
// 从选中值中移除父节点和所有子节点
ids = (_searchParam.value[item.prop] || []).filter((id: any) => !childIds.includes(id) && id !== removedNode.id);
nextTick(() => {
_searchParam.value[item.prop] = ids;
_searchParam.value[item.prop1] = ids.join(",");
});
} else {
// 是子节点,需要找到其父节点并删除
const parentNode = findParentNode(allNodes, removedValue);
if (parentNode) {
// 从选中值中移除子节点和父节点
ids = (_searchParam.value[item.prop] || []).filter((id: any) => id !== removedValue && id !== parentNode.id);
nextTick(() => {
_searchParam.value[item.prop] = ids;
_searchParam.value[item.prop1] = ids.join(",");
});
} else {
ids = (_searchParam.value[item.prop] || []).filter((id: any) => id !== removedValue && id !== parentNode.id);
nextTick(() => {
_searchParam.value[item.prop] = ids;
_searchParam.value[item.prop1] = ids.join(",");
});
}
}
}
syncCheckedIds(item);
});
};
// 辅助方法:查找节点
const findNode = (nodes: any[], value: any): any => {
if (!Array.isArray(nodes)) return null;
for (const node of nodes) {
if (node?.id === value) {
return node;
}
if (node?.children && Array.isArray(node.children) && node.children.length > 0) {
const found = findNode(node.children, value);
if (found) return found;
}
}
return null;
};
// 辅助方法:查找父节点
const findParentNode = (nodes: any[], value: any, parent: any = null): any => {
if (!Array.isArray(nodes)) return null;
for (const node of nodes) {
if (node?.id === value) {
return parent;
}
if (node?.children && Array.isArray(node.children) && node.children.length > 0) {
const foundParent = findParentNode(node.children, value, node);
if (foundParent) return foundParent;
}
}
return null;
};
// 辅助方法获取所有子节点ID
const getAllChildIds = (node: any): any[] => {
let ids: any[] = [];
if (node?.children && Array.isArray(node.children) && node.children.length > 0) {
for (const child of node.children) {
if (child?.id) {
ids.push(child.id);
ids = [...ids, ...getAllChildIds(child)];
}
}
}
return ids;
};
// 统一同步选中ID的方法
const syncCheckedIds = (item: any) => {
// 获取所有全选中的节点(包括父节点)
const allCheckedNodes = treeSelectRef.value.getCheckedNodes(false, false);
const allCheckedIds = allCheckedNodes.map((node: any) => node.id);
_searchParam.value[item.prop] = allCheckedIds;
// 同步到搜索参数
_searchParam.value[item.prop1] = allCheckedIds.length ? allCheckedIds.join(",") : null;
};
const handleTreeSelectChange = (item: any) => {
console.log(routeName.value);
if (routeName.value === "articleListIndex") {
// 通过ref获取组件实例
if (treeSelectRef.value) {
syncCheckedIds(item);
return;
}
}
if (_searchParam.value[item.prop].length) {
let values = cloneDeep(_searchParam.value[item.prop]);
_searchParam.value[item.prop1] = values.join(",");
@@ -236,7 +340,7 @@ const handleClear = (item: any) => {
const handleInput = (item: any) => {
console.log(item, "=====item=====");
//验证
// verificationInput(item, _searchParam, selectInputValue.value);
verificationInput(item, _searchParam, selectInputValue.value);
};
const handleChange = (item: any) => {
_searchParam.value[item.endProp] = "";
@@ -249,16 +353,6 @@ const handleChange = (item: any) => {
const handleEmitClear = (item: any) => {
console.log(item);
if (routeName.value === "barCode") {
$Bus.emit("clearBarCodeCreateUser");
}
if (routeName.value === "boxCode") {
$Bus.emit("clearBoxCodeCreateUser");
}
if (routeName.value === "boxMarkIndex") {
$Bus.emit("clearBoxMarkIndexCreator");
}
};
</script>
<style lang="scss" scope>

View File

@@ -0,0 +1,299 @@
<template>
<div>
<!-- 输入框 -->
<template v-if="item.type === 'input'">
<el-input
:placeholder="item.placeholder"
:maxlength="item.maxlength || 255"
v-model="_searchParam[`${item.prop}`]"
style="width: 224px"
@input="handleInput(item)"
@keyup.enter="search"
clearable
@clear="handleEmitClear(item)"
/>
</template>
<!-- 下拉框 -->
<template v-if="item.type === 'select'">
<el-select
v-model="_searchParam[`${item.prop}`]"
:placeholder="item.placeholder"
clearable
ref="selectRef"
style="width: 224px"
>
<el-option v-for="option in item.options" :label="option.label" :value="option.value" :key="option.label" />
</el-select>
</template>
<!-- 开始-结束-日期选择器 -->
<template v-if="item.type === 'daterange'">
<el-date-picker
v-model="_searchParam[`${item.prop}`]"
:type="item.type"
:start-placeholder="item.startPlaceholder"
:end-placeholder="item.endPlaceholder"
:defaultTime="item.value"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 205px"
@change="handlePicker(item)"
/>
</template>
<!-- 远程搜索 -->
<template v-if="item.type === 'selectRemote'">
<el-select
v-model="_searchParam[`${item.prop}`]"
:placeholder="item.placeholder"
clearable
remote
filterable
@clear="handleClear(item)"
:loading="loading"
class="m-2 select"
remote-show-suffix
:remote-method="
(query:any) => {
remoteMethod(
query,
item
);
}
"
:disabled="item.disabled"
style="width: 224px"
>
<el-option :label="option.name" :value="option.id" v-for="option in item.options" :key="option.id" />
</el-select>
<!--item.prop -->
</template>
<!-- el-tree-select -->
<template v-if="item.type === 'treeSelect'">
<el-tree-select
v-model="_searchParam[`${item.prop}`]"
:data="item.options"
:placeholder="item.placeholder"
multiple
:render-after-expand="false"
:check-strictly="false"
show-checkbox
style="width: 224px"
clearable
:collapse-tags="true"
ref="treeSelectRef"
@change="handleTreeSelectChange(item)"
@remove-tag="handleRemoveTag(item)"
/>
</template>
<!-- 双 -->
<template v-if="item.type === 'inputs'">
<el-input
v-model="_searchParam[`${item.startProp}`]"
:placeholder="item.startPlaceholder"
:disabled="item.disabled"
maxlength="255"
style="width: 105px !important"
@input="handleInput(item)"
>
</el-input>
<span style="margin: 0 3px">-</span>
<el-input
v-model="_searchParam[`${item.endProp}`]"
:placeholder="item.endPlaceholder"
:disabled="item.disabled"
maxlength="255"
style="width: 106px !important"
@input="handleInput(item)"
/>
</template>
<template v-if="item.type === 'dateTimerange'">
<el-date-picker
v-model="_searchParam[`${item.prop}`]"
type="datetimerange"
range-separator=""
:start-placeholder="item.startPlaceholder"
:end-placeholder="item.endPlaceholder"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 205px"
/>
</template>
<template v-if="item.type === 'selectInputs'">
<div></div>
<el-select
v-model="selectInputValue"
placeholder="Select"
style="width: 102px; height: 30px; margin-right: 6px"
class="selectInputs-box"
@change="handleChange(item)"
>
<el-option
v-for="optionsItem in options"
:key="optionsItem.value"
:label="optionsItem.label"
:value="optionsItem.value"
/>
</el-select>
<el-input
v-model="_searchParam[`${item.startProp}`]"
:placeholder="item.startPlaceholder"
:disabled="item.disabled"
maxlength="255"
style="width: 105px !important"
@input="handleInput(item)"
>
</el-input>
<span style="margin: 0 3px">-</span>
<el-input
v-model="_searchParam[`${item.endProp}`]"
:placeholder="item.endPlaceholder"
:disabled="item.disabled"
maxlength="255"
style="width: 106px !important"
@input="handleInput(item)"
/>
</template>
</div>
</template>
<script lang="ts" setup name="SearchFormItem">
// import { verificationInput } from "./utils/verificationInput";
import { getCountryListApi } from "@/api/modules/global";
import $Bus from "@/utils/mittBus";
import { cloneDeep } from "lodash-es";
// import { ref } from "vue";
const $router = useRouter();
const routeName: any = ref($router.currentRoute.value.name);
const treeSelectRef = ref<any>(null);
// const userStore: any = useUserStore();
interface SearchFormItem {
item: { [key: string]: any };
searchParam: { [key: string]: any };
search: (params: any) => void; // 搜索方法
handleEmitClear?: (item: any) => void;
}
let selectInputValue = ref(1);
const options = [
{
value: 1,
label: "序号"
},
{
value: 2,
label: "数字序列号"
}
];
// const treeSelectValue = ref(null);
const props = defineProps<SearchFormItem>();
const _searchParam = computed(() => props.searchParam);
let loading = ref(false);
//日期选择后重选赋值
const handlePicker = (item: any) => {
const { prop } = item;
if (Array.isArray(_searchParam.value[prop]) && _searchParam.value[prop].length > 0) {
let _date: any = cloneDeep(_searchParam.value[prop]);
_date[0] = _date[0] + " " + "00:00:00";
_date[1] = _date[1] + " " + "23:59:59";
_searchParam.value[item.startDate] = _date.join(",");
} else {
_searchParam.value[item.startDate] = "";
}
};
//远程搜索(供应商)
const remoteMethod = async (query: any, item: any) => {
console.log(query, item);
loading.value = true;
if (!query) {
loading.value = false;
return;
}
let valClone = query.replace(/^\s*|\s*$/g, "");
if (!valClone.length) {
loading.value = false;
return;
}
const result = await getCountryListApi({ name: valClone });
if (result?.code === 0) {
const { data } = result;
console.log(data, "=======data=======");
item.options = data;
}
loading.value = false;
};
// 关闭标签时同步
const handleRemoveTag = item => {
console.log("触发了吗");
nextTick(() => {
syncCheckedIds(item);
});
return;
};
// 统一同步选中ID的方法
const syncCheckedIds = (item: any) => {
// 获取所有全选中的节点(包括父节点)
const allCheckedNodes = treeSelectRef.value.getCheckedNodes(false, false);
const allCheckedIds = allCheckedNodes.map((node: any) => node.id);
_searchParam.value[item.prop] = allCheckedIds;
// 同步到搜索参数
_searchParam.value[item.prop1] = allCheckedIds.length ? allCheckedIds.join(",") : null;
};
const handleTreeSelectChange = (item: any) => {
console.log(routeName.value);
if (routeName.value === "articleListIndex") {
// 通过ref获取组件实例
if (treeSelectRef.value) {
syncCheckedIds(item);
return;
}
}
if (_searchParam.value[item.prop].length) {
let values = cloneDeep(_searchParam.value[item.prop]);
_searchParam.value[item.prop1] = values.join(",");
} else {
_searchParam.value[item.prop1] = "";
}
};
const handleClear = (item: any) => {
item.options = [];
};
//input输入监听
const handleInput = (item: any) => {
console.log(item, "=====item=====");
//验证
// verificationInput(item, _searchParam, selectInputValue.value);
};
const handleChange = (item: any) => {
_searchParam.value[item.endProp] = "";
_searchParam.value[item.startProp] = "";
_searchParam.value["serialNumberBegin"] = "";
_searchParam.value["numberCodeBegin"] = "";
_searchParam.value["serialNumberEnd"] = "";
_searchParam.value["numberCodeEnd"] = "";
};
const handleEmitClear = (item: any) => {
console.log(item);
if (routeName.value === "barCode") {
$Bus.emit("clearBarCodeCreateUser");
}
if (routeName.value === "boxCode") {
$Bus.emit("clearBoxCodeCreateUser");
}
if (routeName.value === "boxMarkIndex") {
$Bus.emit("clearBoxMarkIndexCreator");
}
};
</script>
<style lang="scss" scope>
@import "../index.scss";
</style>

View File

@@ -3,6 +3,8 @@
margin-bottom: 8px;
}
.form-item {
display: flex;
align-items: center;
width: 344px !important;
height: 32px;
margin-right: 12px !important;

File diff suppressed because one or more lines are too long