明树Git Lab

Commit 32de73d8 authored by zhanghan's avatar zhanghan

1

parent b8f9fbe3
Pipeline #108525 passed with stage
in 20 seconds
<template>
<div class="search-form">
<el-form
ref="formRef"
:model="formData"
:inline="inline"
:label-width="labelWidth"
:size="size"
@submit.prevent="handleSearch"
>
<el-row :gutter="gutter">
<el-col
v-for="(item, index) in formItems"
:key="item.prop || index"
:span="item.span || defaultSpan"
>
<el-form-item :label="item.label" :prop="item.prop">
<!-- 输入框 -->
<el-input
v-if="item.type === 'input'"
v-model="formData[item.prop]"
:placeholder="item.placeholder || `请输入${item.label}`"
:clearable="item.clearable !== false"
:disabled="item.disabled"
:maxlength="item.maxlength"
@keyup.enter="handleEnterSearch(item)"
@clear="handleFieldClear(item)"
/>
<!-- 选择器 -->
<el-select
v-else-if="item.type === 'select'"
v-model="formData[item.prop]"
:placeholder="item.placeholder || `请选择${item.label}`"
:clearable="item.clearable !== false"
:disabled="item.disabled"
:multiple="item.multiple"
:filterable="item.filterable"
@clear="handleFieldClear(item)"
@change="handleFieldChange(item, $event)"
>
<el-option
v-for="option in item.options"
:key="option.value"
:label="option.label"
:value="option.value"
:disabled="option.disabled"
/>
</el-select>
<!-- 字典选择器 -->
<common-selector
v-else-if="item.type === 'dict-select'"
v-model="formData[item.prop]"
:dict-name="item.dictName"
:label-key="item.labelKey || 'name'"
:value-key="item.valueKey || 'key'"
:placeholder="item.placeholder || `请选择${item.label}`"
:disabled="item.disabled"
:radio="item.radio"
@change="handleFieldChange(item, $event)"
/>
<!-- 日期选择器 -->
<el-date-picker
v-else-if="item.type === 'date'"
v-model="formData[item.prop]"
:type="item.dateType || 'date'"
:placeholder="item.placeholder || `请选择${item.label}`"
:format="item.format"
:value-format="item.valueFormat"
:clearable="item.clearable !== false"
:disabled="item.disabled"
:start-placeholder="item.startPlaceholder"
:end-placeholder="item.endPlaceholder"
@clear="handleFieldClear(item)"
@change="handleFieldChange(item, $event)"
/>
<!-- 日期范围选择器 -->
<el-date-picker
v-else-if="item.type === 'daterange'"
v-model="formData[item.prop]"
type="daterange"
range-separator="至"
:start-placeholder="item.startPlaceholder || '开始日期'"
:end-placeholder="item.endPlaceholder || '结束日期'"
:format="item.format"
:value-format="item.valueFormat"
:clearable="item.clearable !== false"
:disabled="item.disabled"
@clear="handleFieldClear(item)"
@change="handleFieldChange(item, $event)"
/>
<!-- 单选框组 -->
<el-radio-group
v-else-if="item.type === 'radio'"
v-model="formData[item.prop]"
:disabled="item.disabled"
@change="handleFieldChange(item, $event)"
>
<el-radio
v-for="option in item.options"
:key="option.value"
:label="option.value"
>
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 复选框组 -->
<el-checkbox-group
v-else-if="item.type === 'checkbox'"
v-model="formData[item.prop]"
:disabled="item.disabled"
@change="handleFieldChange(item, $event)"
>
<el-checkbox
v-for="option in item.options"
:key="option.value"
:label="option.value"
>
{{ option.label }}
</el-checkbox>
</el-checkbox-group>
<!-- 数字输入框 -->
<el-input-number
v-else-if="item.type === 'number'"
v-model="formData[item.prop]"
:min="item.min"
:max="item.max"
:step="item.step || 1"
:disabled="item.disabled"
:controls="item.controls !== false"
@keyup.enter="handleEnterSearch(item)"
@change="handleFieldChange(item, $event)"
/>
<!-- 级联选择器 -->
<el-cascader
v-else-if="item.type === 'cascader'"
v-model="formData[item.prop]"
:options="item.options"
:props="item.props || {}"
:clearable="item.clearable !== false"
:disabled="item.disabled"
:filterable="item.filterable"
@clear="handleFieldClear(item)"
@change="handleFieldChange(item, $event)"
/>
<!-- 树选择器 -->
<el-tree-select
v-else-if="item.type === 'tree'"
v-model="formData[item.prop]"
:data="item.data"
:props="item.props || {}"
:clearable="item.clearable !== false"
:disabled="item.disabled"
:filterable="item.filterable"
:check-strictly="item.checkStrictly"
@clear="handleFieldClear(item)"
@change="handleFieldChange(item, $event)"
/>
<!-- 自定义插槽 -->
<slot
v-else-if="item.type === 'slot'"
:name="item.slotName || item.prop"
:prop="item.prop"
:item="item"
:value="formData[item.prop]"
:onChange="(value) => handleSlotChange(item, value)"
/>
</el-form-item>
</el-col>
<!-- 操作按钮 -->
<el-col :span="buttonSpan || 6">
<el-form-item>
<div class="search-form-buttons">
<el-button type="primary" :icon="Search" @click="handleSearch">
{{ searchText || "搜索" }}
</el-button>
<el-button :icon="RefreshLeft" @click="handleReset">
{{ resetText || "重置" }}
</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script setup>
import { ref, reactive, watch, onMounted } from "vue";
import { Search, RefreshLeft } from "@element-plus/icons-vue";
import CommonSelector from "@/components/CommonSelector.vue";
const props = defineProps({
// 表单项配置
items: {
type: Array,
default: () => [],
},
// 表单数据
modelValue: {
type: Object,
default: () => ({}),
},
// 是否行内表单
inline: {
type: Boolean,
default: true,
},
// 标签宽度
labelWidth: {
type: String,
default: "auto",
},
// 表单尺寸
size: {
type: String,
default: "default",
},
// 栅格间隔
gutter: {
type: Number,
default: 16,
},
// 默认每个表单项占的列数
defaultSpan: {
type: Number,
default: 6,
},
// 按钮列数
buttonSpan: {
type: Number,
default: 6,
},
// 搜索按钮文本
searchText: {
type: String,
default: "搜索",
},
// 重置按钮文本
resetText: {
type: String,
default: "重置",
},
// 是否在重置时自动搜索
autoSearchOnReset: {
type: Boolean,
default: true,
},
// 是否在字段清空时自动搜索
autoSearchOnClear: {
type: Boolean,
default: false,
},
});
const emit = defineEmits([
"update:modelValue",
"search",
"reset",
"field-change",
"field-clear",
"enter-search",
]);
const formRef = ref();
const formData = reactive({});
// 表单项配置
const formItems = props.items;
// 初始化表单数据
const initFormData = () => {
Object.keys(formData).forEach((key) => {
delete formData[key];
});
formItems.forEach((item) => {
if (item.prop) {
if (props.modelValue[item.prop] !== undefined) {
formData[item.prop] = props.modelValue[item.prop];
} else {
formData[item.prop] =
item.defaultValue !== undefined
? item.defaultValue
: getDefaultValue(item.type);
}
}
});
};
// 获取不同类型的默认值
const getDefaultValue = (type) => {
switch (type) {
case "checkbox":
return [];
case "number":
return null;
case "daterange":
return [];
default:
return "";
}
};
// 监听表单数据变化
watch(
formData,
(newVal) => {
emit("update:modelValue", { ...newVal });
},
{ deep: true },
);
// 监听外部数据变化
watch(
() => props.modelValue,
(newVal) => {
Object.keys(newVal).forEach((key) => {
if (formData.hasOwnProperty(key)) {
formData[key] = newVal[key];
}
});
},
{ deep: true },
);
// 搜索处理
const handleSearch = () => {
emit("search", { ...formData });
};
// 重置处理
const handleReset = () => {
formRef.value?.resetFields();
initFormData();
emit("reset", { ...formData });
if (props.autoSearchOnReset) {
emit("search", { ...formData });
}
};
// 字段变化处理
const handleFieldChange = (item, value) => {
emit("field-change", item.prop, value, formData);
};
// 字段清空处理
const handleFieldClear = (item) => {
emit("field-clear", item.prop, formData);
if (props.autoSearchOnClear) {
emit("search", { ...formData });
}
};
// 插槽变化处理
const handleSlotChange = (item, value) => {
formData[item.prop] = value;
emit("field-change", item.prop, value, formData);
};
// 回车搜索处理
const handleEnterSearch = (item) => {
emit("enter-search", item.prop, formData);
// 某些输入框可能需要在回车时触发搜索
if (item.searchOnEnter !== false) {
handleSearch();
}
};
// 暴露方法
defineExpose({
formRef,
formData,
resetFields: handleReset,
search: handleSearch,
});
onMounted(() => {
initFormData();
});
</script>
<style lang="less" scoped>
.search-form {
:deep(.el-form-item) {
margin-bottom: 12px;
}
:deep(.el-form-item__label) {
font-weight: normal;
}
:deep(.el-input),
:deep(.el-select),
:deep(.el-date-editor),
:deep(.el-cascader),
:deep(.el-tree-select) {
width: 100%;
}
.search-form-buttons {
display: flex;
gap: 8px;
}
:deep(.el-input-number) {
width: 100%;
}
}
</style>
# SearchForm 通用搜索表单组件使用说明
## 组件位置
`@/components/common/SearchForm.vue`
## 功能特性
- 支持多种表单控件类型(输入框、选择器、日期选择器等)
- 支持字典选择器(使用 CommonSelector 组件)
- 支持搜索、重置功能
- 支持单个字段清空回调
- 支持回车触发搜索
- 支持显示/隐藏搜索区域
- 灵活的布局配置
## 基本用法
### 1. 引入组件
```vue
import SearchForm from '@/components/common/SearchForm.vue'
```
### 2. 基本示例
```vue
<template>
<div>
<search-form
ref="searchFormRef"
v-model="searchForm"
:items="searchItems"
@search="handleSearch"
@reset="handleReset"
@field-clear="handleFieldClear"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 搜索表单数据
const searchForm = ref({})
// 搜索字段配置
const searchItems = ref([
{
type: 'input',
label: '项目名称',
prop: 'projectName',
placeholder: '请输入项目名称',
clearable: true,
span: 6
},
{
type: 'input',
label: '项目编号',
prop: 'projectCode',
placeholder: '请输入项目编号',
clearable: true,
span: 6
}
])
// 搜索处理
const handleSearch = (formData) => {
console.log('搜索参数:', formData)
// 调用你的列表数据获取方法
getProjectData(formData)
}
// 重置处理
const handleReset = (formData) => {
console.log('重置后的参数:', formData)
}
// 单个字段清空处理
const handleFieldClear = (prop, formData) => {
console.log('字段清空:', prop, formData)
}
</script>
```
## 支持的字段类型
### 1. input - 输入框
```javascript
{
type: 'input',
label: '项目名称',
prop: 'projectName',
placeholder: '请输入项目名称',
clearable: true, // 是否显示清空按钮
disabled: false, // 是否禁用
maxlength: 50, // 最大长度
span: 6, // 栅格占用的列数
searchOnEnter: true // 回车时是否触发搜索(默认true)
}
```
### 2. select - 下拉选择器
```javascript
{
type: 'select',
label: '项目状态',
prop: 'projectLzType',
placeholder: '请选择项目状态',
clearable: true,
span: 6,
options: [
{ label: '待立项', value: '1' },
{ label: '已立项', value: '5' }
]
}
```
### 3. dict-select - 字典选择器(推荐)
```javascript
{
type: 'dict-select',
label: '项目类型',
prop: 'projectType',
dictName: 'xmlx', // 必传:字典名称(从 sessionStorage 的 resourceData 中获取)
placeholder: '请选择项目类型',
span: 6,
labelKey: 'name', // 可选:标签字段(默认 'name')
valueKey: 'key', // 可选:值字段(默认 'key')
radio: false // 可选:是否使用单选组(默认 false,使用下拉)
}
```
### 4. date - 日期选择器
```javascript
{
type: 'date',
label: '创建时间',
prop: 'createTime',
dateType: 'date', // date/datetime/month/year 等
placeholder: '请选择日期',
valueFormat: 'YYYY-MM-DD',
format: 'YYYY-MM-DD',
clearable: true,
span: 6
}
```
### 5. daterange - 日期范围选择器
```javascript
{
type: 'daterange',
label: '时间范围',
prop: 'timeRange',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
valueFormat: 'YYYY-MM-DD',
clearable: true,
span: 6
}
```
### 6. number - 数字输入框
```javascript
{
type: 'number',
label: '金额',
prop: 'amount',
min: 0,
max: 1000000,
step: 100,
span: 6
}
```
### 7. radio - 单选框组
```javascript
{
type: 'radio',
label: '状态',
prop: 'status',
span: 6,
options: [
{ label: '启用', value: '1' },
{ label: '禁用', value: '0' }
]
}
```
### 8. checkbox - 复选框组
```javascript
{
type: 'checkbox',
label: '权限',
prop: 'permissions',
span: 6,
options: [
{ label: '查看', value: 'view' },
{ label: '编辑', value: 'edit' }
]
}
```
### 9. cascader - 级联选择器
```javascript
{
type: 'cascader',
label: '地区',
prop: 'region',
options: [...],
props: {
value: 'value',
label: 'label',
children: 'children'
},
clearable: true,
span: 6
}
```
### 10. tree - 树选择器
```javascript
{
type: 'tree',
label: '部门',
prop: 'department',
data: [...], // 树形数据
checkStrictly: true, // 是否可选择任意节点
clearable: true,
span: 6
}
```
## Props 参数
| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| items | 表单项配置数组 | Array | [] |
| modelValue | 表单数据(v-model) | Object | {} |
| inline | 是否行内表单 | Boolean | true |
| labelWidth | 标签宽度 | String | 'auto' |
| size | 表单尺寸 | String | 'default' |
| gutter | 栅格间隔 | Number | 16 |
| defaultSpan | 默认每个表单项占的列数 | Number | 6 |
| buttonSpan | 按钮列数 | Number | 6 |
| searchText | 搜索按钮文本 | String | '搜索' |
| resetText | 重置按钮文本 | String | '重置' |
| autoSearchOnReset | 重置时是否自动搜索 | Boolean | true |
| autoSearchOnClear | 字段清空时是否自动搜索 | Boolean | false |
## Events 事件
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| search | 点击搜索按钮时触发 | (formData: Object) |
| reset | 点击重置按钮时触发 | (formData: Object) |
| field-change | 字段值变化时触发 | (prop: String, value: Any, formData: Object) |
| field-clear | 字段清空时触发 | (prop: String, formData: Object) |
| enter-search | 回车键触发时触发 | (prop: String, formData: Object) |
## 组件方法(通过 ref 调用)
```javascript
// 手动触发搜索
searchFormRef.value.search()
// 手动重置表单
searchFormRef.value.resetFields()
// 访问表单数据
console.log(searchFormRef.value.formData)
```
## 完整示例(项目列表页)
```vue
<template>
<div class="manage-container">
<div class="manage-wrap">
<!-- 搜索表单区域 -->
<div class="manage-search" v-if="showSearch">
<search-form
ref="searchFormRef"
v-model="searchForm"
:items="searchItems"
@search="handleSearch"
@reset="handleReset"
@field-clear="handleFieldClear"
/>
</div>
<div class="manage-header">
<div class="header-left">
<el-button
:icon="showSearch ? ArrowUp : ArrowDown"
@click="toggleSearch"
>
{{ showSearch ? '隐藏搜索' : '显示搜索' }}
</el-button>
</div>
</div>
<!-- 列表内容 -->
<div class="manage-content">
<!-- 你的表格组件 -->
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
import SearchForm from '@/components/common/SearchForm.vue'
const showSearch = ref(true)
const searchFormRef = ref()
const searchForm = ref({})
const searchItems = ref([
{
type: 'input',
label: '项目名称',
prop: 'projectName',
placeholder: '请输入项目名称',
clearable: true,
span: 6
},
{
type: 'dict-select',
label: '项目类型',
prop: 'projectType',
dictName: 'xmlx',
placeholder: '请选择项目类型',
span: 6
},
{
type: 'daterange',
label: '创建时间',
prop: 'createTime',
startPlaceholder: '开始日期',
endPlaceholder: '结束日期',
valueFormat: 'YYYY-MM-DD',
span: 6
}
])
const toggleSearch = () => {
showSearch.value = !showSearch.value
}
const handleSearch = (formData) => {
console.log('搜索参数:', formData)
currentPage.value = 1
getProjectData(formData)
}
const handleReset = (formData) => {
console.log('重置后的参数:', formData)
currentPage.value = 1
}
const handleFieldClear = (prop, formData) => {
console.log('字段清空:', prop, formData)
}
const getProjectData = (params = {}) => {
// 你的数据获取逻辑
console.log('获取列表数据:', params)
}
</script>
<style scoped lang="less">
.manage-search {
padding: 16px;
background: #fff;
margin-bottom: 16px;
border-radius: 4px;
}
</style>
```
## 注意事项
1. **字典选择器使用**:确保 sessionStorage 中有 `resourceData` 数据,且包含对应的字典名称
2. **字段清空**:默认情况下,字段清空不会自动触发搜索,如需自动搜索,设置 `autoSearchOnClear: true`
3. **重置行为**:默认重置后会自动触发搜索,如需关闭,设置 `autoSearchOnReset: false`
4. **回车搜索**:输入框和数字输入框支持回车触发搜索,可通过 `searchOnEnter: false` 关闭
5. **布局调整**:通过调整 `defaultSpan` 和各字段的 `span` 属性来控制布局
......@@ -270,7 +270,7 @@ const handleLogout = () => {
.city-header {
width: 100%;
height: 48px;
background-color: #1890ff;
background: linear-gradient(135deg, #1890ff 0%, #40a9ff 50%, #69c0ff 100%);
color: #fff;
display: flex;
align-items: center;
......@@ -348,11 +348,7 @@ const handleLogout = () => {
// 标签页容器样式
.tabs-view {
background: #fff;
margin: 16px 16px 0 16px;
padding: 10px 16px;
border-radius: 8px;
border-bottom: 1px solid #e4e7ed;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
padding: 8px;
:deep(.el-tabs) {
.el-tabs__header {
......@@ -365,28 +361,26 @@ const handleLogout = () => {
}
.el-tabs__item {
margin-top: 0;
height: 32px;
line-height: 32px;
border: 1px solid #d8dce5;
border-radius: 3px;
margin-right: 8px;
color: #495060;
font-size: 12px;
padding: 0 12px;
background: #fff;
background: #f5f5f5;
transition: all 0.2s;
border-top: 2px solid #d8dce5;
&:hover {
color: #3d84ee;
background: #ecf3fd;
color: #fff;
background: #1890ff;
}
&.is-active {
color: #3d84ee;
background: #ecf3fd;
border-color: #3d84ee;
color: #fff;
background: #1890ff;
border-color: #1890ff;
}
}
......
......@@ -35,6 +35,12 @@
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.manage-search {
padding: 16px;
background: #fff;
margin-bottom: 16px;
border-radius: 4px;
}
.manage-content {
flex: 1;
height: 0;
......@@ -43,6 +49,7 @@
height: 100%;
display: flex;
flex-direction: column;
border-radius: 0;
}
.manage-content .common-table .table-container {
flex: 1;
......@@ -57,26 +64,24 @@
.manage-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
background: rgba(157, 188, 218, 0.1);
}
.manage-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.manage-header {
padding-top: 16px;
padding-right: 16px;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
padding-bottom: 10px;
background-color: #fff;
}
.manage-content {
flex: 1;
......@@ -102,7 +107,7 @@
.add-project-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
......@@ -199,6 +204,32 @@
max-height: 120px;
overflow: auto;
}
.add-project-content .tab-content h3 {
text-align: center;
}
.add-project-content .tab-content .text-border {
width: 100%;
padding: 0 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #f5f7fa;
min-height: 34px;
}
.add-project-content .tab-content .report-item {
display: flex;
align-items: center;
margin: 18px 0;
}
.add-project-content .tab-content .report-label {
width: 150px;
text-align: right;
padding-right: 12px;
}
.add-project-content .tab-content .report-content {
border-left: 1px solid #eaeaea;
flex: 1;
width: 0;
}
.add-project-content .always-click {
padding: 2px;
font-size: 12px;
......
......@@ -35,6 +35,13 @@
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.manage-search {
padding: 16px;
background: #fff;
margin-bottom: 16px;
border-radius: 4px;
}
.manage-content {
flex: 1;
height: 0;
......@@ -42,6 +49,8 @@
height: 100%;
display: flex;
flex-direction: column;
border-radius: 0;
.table-container {
flex: 1;
height: 0;
......@@ -58,27 +67,25 @@
&-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
background: rgba(157, 188, 218, 0.1);
}
&-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
&-header {
padding-top: 16px;
padding-right: 16px;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
padding-bottom: 10px;
background-color: #fff;
}
&-content {
flex: 1;
......@@ -107,7 +114,7 @@
&-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
......@@ -204,31 +211,31 @@
overflow: auto;
}
}
h3{
text-align: center;
h3 {
text-align: center;
}
.text-border{
width: 100%;
padding: 0 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #f5f7fa;
min-height: 34px;
.text-border {
width: 100%;
padding: 0 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #f5f7fa;
min-height: 34px;
}
.report-item{
display: flex;
align-items: center;
margin: 18px 0;
.report-item {
display: flex;
align-items: center;
margin: 18px 0;
}
.report-label{
width: 150px;
text-align: right;
padding-right: 12px;
.report-label {
width: 150px;
text-align: right;
padding-right: 12px;
}
.report-content{
border-left: 1px solid #eaeaea;
flex: 1;
width: 0;
.report-content {
border-left: 1px solid #eaeaea;
flex: 1;
width: 0;
}
}
.always-click {
......
......@@ -30,9 +30,15 @@
.system-manage-content {
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 20px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.manage-search {
padding: 16px;
background: #fff;
margin-bottom: 16px;
border-radius: 4px;
}
.manage-content {
flex: 1;
height: 0;
......@@ -55,21 +61,16 @@
.manage-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
background: rgba(157, 188, 218, 0.1);
}
.manage-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.manage-header {
display: flex;
......@@ -86,6 +87,7 @@
height: 100%;
display: flex;
flex-direction: column;
border-radius: 0;
}
.manage-content .common-table .table-container {
flex: 1;
......@@ -100,7 +102,7 @@
::v-deep.add-project-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
......
......@@ -6,6 +6,7 @@
flex-direction: column;
box-sizing: border-box;
}
.system-manage-header {
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
......@@ -32,9 +33,16 @@
.system-manage-content {
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 20px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.manage-search {
padding: 16px;
background: #fff;
margin-bottom: 16px;
border-radius: 4px;
}
.manage-content {
flex: 1;
height: 0;
......@@ -58,21 +66,16 @@
&-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
background: rgba(157, 188, 218, 0.1);
}
&-wrap {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: rgba(255, 255, 255, 0.9);
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
&-header {
......@@ -89,6 +92,7 @@
height: 100%;
display: flex;
flex-direction: column;
border-radius: 0;
.table-container {
flex: 1;
height: 0;
......@@ -107,7 +111,7 @@
&-container {
width: 100%;
height: 100%;
padding: 20px;
padding: 16px;
box-sizing: border-box;
display: flex;
flex-direction: column;
......
<template>
<div class="manage-container">
<div class="manage-wrap">
<!-- 搜索表单区域 -->
<div class="manage-search" v-if="showSearch">
<search-form
v-model="searchForm"
:items="searchItems"
@search="handleSearch"
@reset="handleReset"
@field-clear="handleFieldClear"
/>
</div>
<div class="manage-header">
<div class="header-left"></div>
<div class="header-right">
......@@ -71,7 +82,9 @@
<script setup>
import { reactive, ref, onMounted, computed, getCurrentInstance } from "vue";
import { useRouter } from "vue-router";
import { ArrowUp, ArrowDown } from "@element-plus/icons-vue";
import CommonTable from "@/components/common/commonTable.vue";
import SearchForm from "@/components/common/SearchForm.vue";
const router = useRouter();
const { proxy } = getCurrentInstance();
......@@ -171,7 +184,7 @@ const confirmFieldsModal = () => {
: data.projectLzType === "9"
? "已决策"
: "待立项";
}
},
},
{
prop: "operations",
......@@ -180,7 +193,7 @@ const confirmFieldsModal = () => {
slot: "operations",
fixed: "right",
align: "center",
}
},
]);
filedsModalShow.value = false;
};
......@@ -189,17 +202,117 @@ let loading = ref(false);
let total = ref(0);
let currentPage = ref(1);
let pageSize = ref(10);
// 获取列表数据
const getProjectData = () => {
// ========== 搜索表单相关 ==========
const showSearch = ref(true);
const searchForm = ref({});
// 搜索字段配置
const searchItems = ref([
{
type: "input",
label: "项目名称",
prop: "projectName",
placeholder: "请输入项目名称",
clearable: true,
span: 6,
},
{
type: "input",
label: "项目编号",
prop: "projectCode",
placeholder: "请输入项目编号",
clearable: true,
span: 6,
},
{
type: "input",
label: "直属企业",
prop: "zsqy",
placeholder: "请输入直属企业",
clearable: true,
span: 6,
},
{
type: "input",
label: "管理主体",
prop: "glzt",
placeholder: "请输入管理主体",
clearable: true,
span: 6,
},
{
type: "input",
label: "联系人",
prop: "lxr",
placeholder: "请输入联系人",
clearable: true,
span: 6,
},
{
type: "dict-select",
label: "项目阶段",
prop: "xmjd",
dictName: "xmjd",
placeholder: "请选择项目阶段",
span: 6,
},
{
type: "dict-select",
label: "项目区域",
prop: "xmqy",
dictName: "xmqy",
placeholder: "请选择项目区域",
span: 6,
},
]);
// 搜索处理
const handleSearch = (formData) => {
console.log("搜索参数:", formData);
currentPage.value = 1;
getProjectData(formData);
};
// 重置处理
const handleReset = (formData) => {
currentPage.value = 1;
getProjectData();
};
// 单个字段清空处理
const handleFieldClear = (prop, formData) => {
console.log("字段清空:", prop, formData);
};
// ========== 获取列表数据 ==========
const getProjectData = (params = {}) => {
loading.value = true;
// 构建查询参数
const queryParams = {
page: currentPage.value,
pagesize: pageSize.value,
attributes: [],
menuType: "xmdak",
};
// 处理搜索条件
if (params.projectName) {
queryParams.projectName = params.projectName;
}
if (params.projectCode) {
queryParams.projectCode = params.projectCode;
}
if (params.projectLzType) {
queryParams.projectLzType = params.projectLzType;
}
// 可以继续添加其他搜索字段的处理
proxy.$post({
url: "/api/project/listProject",
data: {
page: currentPage.value,
pagesize: pageSize.value,
attributes: [],
menuType: "xmdak",
},
data: queryParams,
callback: (data) => {
tableData.value = data.rows;
total.value = data.count;
......@@ -216,11 +329,11 @@ onMounted(() => {
const handleSizeChange = (size) => {
pageSize.value = size;
currentPage.value = 1;
getProjectData();
getProjectData(searchForm.value);
};
const handleCurrentPageChange = (page) => {
currentPage.value = page;
getProjectData();
getProjectData(searchForm.value);
};
const previewProject = (item) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment