feat(projects): 新增项目、执行、任务等功能

This commit is contained in:
2026-05-09 11:30:34 +08:00
parent f4f43814b3
commit 824392b564
106 changed files with 13060 additions and 1049 deletions

View File

@@ -298,6 +298,14 @@ async function handleSearchDictType() {
await getDictTypeList();
}
async function resetDictTypeSearchParams() {
const pageSize = dictTypeSearchParams.pageSize;
Object.assign(dictTypeSearchParams, getInitDictTypeSearchParams(), { pageSize });
await getDictTypeList();
}
async function handleSearchDictData() {
dictDataSearchParams.pageNo = 1;
await getDictDataByPage(1);
@@ -349,7 +357,11 @@ onMounted(() => {
class="min-h-560px gap-16px overflow-hidden xl:grid xl:grid-cols-[360px_minmax(0,1fr)] lt-xl:flex lt-xl:flex-col lt-xl:overflow-auto"
>
<div class="flex-col-stretch gap-16px xl:min-h-0">
<DictTypeSearch v-model:model="dictTypeSearchParams" @search="handleSearchDictType" />
<DictTypeSearch
v-model:model="dictTypeSearchParams"
@reset="resetDictTypeSearchParams"
@search="handleSearchDictType"
/>
<ElCard v-loading="typeLoading" class="card-wrapper xl:flex-1-hidden" body-class="dict-type-card-body">
<template #header>
<div class="flex items-center justify-between gap-12px py-2px">

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { dictStatusOptions } from '@/constants/business';
import TableSearchPanel from '@/components/custom/table-search-panel.vue';
import TableSearchFields, { type SearchField } from '@/components/custom/table-search-fields.vue';
import { $t } from '@/locales';
defineOptions({ name: 'DictDataSearch' });
@@ -9,7 +10,7 @@ interface Props {
disabled?: boolean;
}
withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<Props>(), {
disabled: false
});
@@ -22,6 +23,25 @@ const emit = defineEmits<Emits>();
const model = defineModel<Api.Dict.DictDataSearchParams>('model', { required: true });
const fields = computed<SearchField[]>(() => [
{
key: 'label',
label: $t('page.system.dict.dictLabel'),
type: 'input',
placeholder: $t('page.system.dict.form.dictLabel')
},
{
key: 'status',
label: $t('page.system.dict.dictStatus'),
type: 'select',
placeholder: $t('page.system.dict.form.dictStatus'),
options: dictStatusOptions.map(item => ({
label: $t(item.label),
value: item.value
}))
}
]);
function handleReset() {
emit('reset');
}
@@ -32,37 +52,12 @@ function handleSearch() {
</script>
<template>
<TableSearchPanel
:model="model"
:disabled="disabled"
:action-col-lg="12"
:action-col-md="8"
<TableSearchFields
v-model="model"
:fields="fields"
:columns="3"
:disabled="props.disabled"
@reset="handleReset"
@search="handleSearch"
>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.dict.dictLabel')" prop="label">
<ElInput
v-model="model.label"
clearable
:disabled="disabled"
:placeholder="$t('page.system.dict.form.dictLabel')"
/>
</ElFormItem>
</ElCol>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.dict.dictStatus')" prop="status">
<ElSelect
v-model="model.status"
clearable
:disabled="disabled"
:placeholder="$t('page.system.dict.form.dictStatus')"
>
<ElOption v-for="{ label, value } in dictStatusOptions" :key="value" :label="$t(label)" :value="value" />
</ElSelect>
</ElFormItem>
</ElCol>
</TableSearchPanel>
/>
</template>
<style scoped></style>

View File

@@ -106,8 +106,6 @@ const title = computed(() => {
return titleMap[props.operateType];
});
const dialogWidth = '780px';
const model = ref(createDefaultModel());
function getCurrentScopeParams(): Api.SystemManage.ScopeQueryParams {
@@ -1163,7 +1161,7 @@ watch(visible, value => {
<BusinessFormDialog
v-model="visible"
:title="title"
:width="dialogWidth"
preset="lg"
:loading="detailLoading"
:confirm-loading="submitting"
@confirm="handleSubmit"

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { commonStatusOptions } from '@/constants/business';
import TableSearchPanel from '@/components/custom/table-search-panel.vue';
import TableSearchFields, { type SearchField } from '@/components/custom/table-search-fields.vue';
import { $t } from '@/locales';
defineOptions({ name: 'MenuSearch' });
@@ -22,6 +23,25 @@ const emit = defineEmits<Emits>();
const model = defineModel<Api.SystemManage.MenuSearchParams>('model', { required: true });
const fields = computed<SearchField[]>(() => [
{
key: 'name',
label: $t('page.system.menu.menuName'),
type: 'input',
placeholder: $t('page.system.menu.form.menuName')
},
{
key: 'status',
label: $t('page.system.menu.menuStatus'),
type: 'select',
placeholder: $t('page.system.menu.form.menuStatus'),
options: commonStatusOptions.map(item => ({
label: $t(item.label),
value: item.value
}))
}
]);
function reset() {
emit('reset');
}
@@ -32,27 +52,14 @@ function search() {
</script>
<template>
<TableSearchPanel
:model="model"
<TableSearchFields
v-model="model"
:fields="fields"
:columns="4"
:disabled="props.disabled"
:action-col-lg="8"
:action-col-md="24"
@reset="reset"
@search="search"
>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.menu.menuName')" prop="name">
<ElInput v-model="model.name" clearable :placeholder="$t('page.system.menu.form.menuName')" />
</ElFormItem>
</ElCol>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.menu.menuStatus')" prop="status">
<ElSelect v-model="model.status" clearable class="w-full" :placeholder="$t('page.system.menu.form.menuStatus')">
<ElOption v-for="{ label, value } in commonStatusOptions" :key="value" :label="$t(label)" :value="value" />
</ElSelect>
</ElFormItem>
</ElCol>
</TableSearchPanel>
/>
</template>
<style scoped></style>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed, reactive, watch } from 'vue';
import { postTypeOptions } from '@/constants/business';
import TableSearchPanel from '@/components/custom/table-search-panel.vue';
import TableSearchFields, { type SearchField } from '@/components/custom/table-search-fields.vue';
defineOptions({ name: 'PostSearch' });
@@ -17,17 +17,69 @@ const statusOptions = [
{ label: '停用', value: 1 as const }
];
const keyword = computed({
get() {
return model.value.name ?? model.value.code ?? '';
},
set(value: string) {
const text = value.trim() || undefined;
model.value.name = text;
model.value.code = text;
}
const searchModel = reactive<{
keyword: string;
postType?: Api.SystemManage.PostType | null;
status?: Api.SystemManage.CommonStatus;
}>({
keyword: '',
postType: undefined,
status: undefined
});
let syncingFromSource = false;
watch(
() => [model.value.name, model.value.code, model.value.postType, model.value.status] as const,
([name, code, postType, status]) => {
syncingFromSource = true;
searchModel.keyword = name ?? code ?? '';
searchModel.postType = postType;
searchModel.status = status;
syncingFromSource = false;
},
{ immediate: true, flush: 'sync' }
);
watch(
() => [searchModel.keyword, searchModel.postType, searchModel.status] as const,
([keywordValue, postType, status]) => {
if (syncingFromSource) {
return;
}
const keywordText = keywordValue.trim() || undefined;
model.value.name = keywordText;
model.value.code = keywordText;
model.value.postType = postType;
model.value.status = status;
},
{ flush: 'sync' }
);
const fields = computed<SearchField[]>(() => [
{
key: 'keyword',
label: '岗位名称',
type: 'input',
placeholder: '请输入岗位名称或岗位编码'
},
{
key: 'postType',
label: '岗位类型',
type: 'select',
placeholder: '请选择岗位类型',
options: postTypeOptions
},
{
key: 'status',
label: '岗位状态',
type: 'select',
placeholder: '请选择岗位状态',
options: statusOptions
}
]);
function reset() {
emit('reset');
}
@@ -38,27 +90,7 @@ function search() {
</script>
<template>
<TableSearchPanel :model="model" :action-col-lg="8" @reset="reset" @search="search">
<ElCol :lg="8" :md="12" :sm="12">
<ElFormItem label="岗位名称" prop="name">
<ElInput v-model="keyword" clearable placeholder="请输入岗位名称或岗位编码" />
</ElFormItem>
</ElCol>
<ElCol :lg="8" :md="12" :sm="12">
<ElFormItem label="岗位类型" prop="postType">
<ElSelect v-model="model.postType" clearable placeholder="请选择岗位类型">
<ElOption v-for="{ label, value } in postTypeOptions" :key="value" :label="label" :value="value" />
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :lg="8" :md="12" :sm="12">
<ElFormItem label="岗位状态" prop="status">
<ElSelect v-model="model.status" clearable placeholder="请选择岗位状态">
<ElOption v-for="{ label, value } in statusOptions" :key="value" :label="label" :value="value" />
</ElSelect>
</ElFormItem>
</ElCol>
</TableSearchPanel>
<TableSearchFields v-model="searchModel" :fields="fields" :columns="4" @reset="reset" @search="search" />
</template>
<style scoped></style>

View File

@@ -429,10 +429,6 @@ getMenuTreeData();
}
}
:deep(.el-row) {
margin: 0 0 -15px 0;
}
.role-card-header {
display: flex;
align-items: flex-start;

View File

@@ -167,24 +167,25 @@ watch(visible, value => {
<BusinessFormDialog
v-model="visible"
:title="title"
preset="md"
preset="sm"
:loading="detailLoading"
:confirm-loading="submitting"
:scrollbar="false"
@confirm="handleSubmit"
>
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top">
<ElRow :gutter="16">
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.role.roleName')" prop="name">
<ElInput v-model="model.name" :placeholder="$t('page.system.role.form.roleName')" />
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.role.roleCode')" prop="code">
<ElInput v-model="model.code" :placeholder="$t('page.system.role.form.roleCode')" />
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.role.sort')" prop="sort">
<ElInputNumber
v-model="model.sort"
@@ -194,7 +195,7 @@ watch(visible, value => {
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.role.roleStatus')" prop="status">
<ElRadioGroup v-model="model.status" class="business-form-radio-group">
<ElRadio v-for="{ label, value } in commonStatusOptions" :key="value" :value="value">

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { computed, reactive, watch } from 'vue';
import { commonStatusOptions } from '@/constants/business';
import TableSearchPanel from '@/components/custom/table-search-panel.vue';
import TableSearchFields, { type SearchField } from '@/components/custom/table-search-fields.vue';
import { $t } from '@/locales';
defineOptions({ name: 'RoleSearch' });
@@ -15,17 +15,61 @@ const emit = defineEmits<Emits>();
const model = defineModel<Api.SystemManage.RoleSearchParams>('model', { required: true });
const keyword = computed({
get() {
return model.value.name ?? model.value.code ?? '';
},
set(value: string) {
const text = value.trim() || undefined;
model.value.name = text;
model.value.code = text;
}
const searchModel = reactive<{
keyword: string;
status?: Api.SystemManage.CommonStatus;
}>({
keyword: '',
status: undefined
});
let syncingFromSource = false;
watch(
() => [model.value.name, model.value.code, model.value.status] as const,
([name, code, status]) => {
syncingFromSource = true;
searchModel.keyword = name ?? code ?? '';
searchModel.status = status;
syncingFromSource = false;
},
{ immediate: true, flush: 'sync' }
);
watch(
() => [searchModel.keyword, searchModel.status] as const,
([keywordValue, status]) => {
if (syncingFromSource) {
return;
}
const keywordText = keywordValue.trim() || undefined;
model.value.name = keywordText;
model.value.code = keywordText;
model.value.status = status;
},
{ flush: 'sync' }
);
const fields = computed<SearchField[]>(() => [
{
key: 'keyword',
label: $t('page.system.role.searchKeyword'),
type: 'input',
placeholder: $t('page.system.role.searchPlaceholder')
},
{
key: 'status',
label: $t('page.system.role.roleStatus'),
type: 'select',
placeholder: $t('page.system.role.form.roleStatus'),
options: commonStatusOptions.map(item => ({
label: $t(item.label),
value: item.value
}))
}
]);
function reset() {
emit('reset');
}
@@ -36,20 +80,7 @@ function search() {
</script>
<template>
<TableSearchPanel :model="model" :action-col-lg="8" @reset="reset" @search="search">
<ElCol :lg="8" :md="12" :sm="12">
<ElFormItem :label="$t('page.system.role.searchKeyword')" prop="name">
<ElInput v-model="keyword" clearable :placeholder="$t('page.system.role.searchPlaceholder')" />
</ElFormItem>
</ElCol>
<ElCol :lg="8" :md="12" :sm="12">
<ElFormItem :label="$t('page.system.role.roleStatus')" prop="status">
<ElSelect v-model="model.status" clearable :placeholder="$t('page.system.role.form.roleStatus')">
<ElOption v-for="{ label, value } in commonStatusOptions" :key="value" :label="$t(label)" :value="value" />
</ElSelect>
</ElFormItem>
</ElCol>
</TableSearchPanel>
<TableSearchFields v-model="searchModel" :fields="fields" :columns="3" @reset="reset" @search="search" />
</template>
<style scoped></style>

View File

@@ -134,7 +134,7 @@ async function loadTreeData() {
if (!error) {
treeData.value = data || [];
// 数据加载完成后,展开前两层节点
await nextTick();
expandFirstTwoLevels();
@@ -173,7 +173,7 @@ async function loadTreeDataByQuery(query: Api.SystemManage.UserManagementRelatio
async function reloadTreeData() {
// 保存当前展开状态
saveExpandedState();
checkedNodeKeys.value = [];
await loadTreeData();
await nextTick();
@@ -236,10 +236,10 @@ const isAddFromTreeNode = ref(false);
*/
function openAdd(item?: Api.SystemManage.UserManagementRelationTreeRespVO) {
operateType.value = 'add';
// 如果是从树节点点击的新增按钮,标记为来自树节点
isAddFromTreeNode.value = Boolean(item);
// 如果是从某一行的新增按钮触发,则默认上级为当前节点用户
// 否则默认上级为当前登录用户(在对话框组件中处理)
editingData.value = item
@@ -364,17 +364,17 @@ function saveExpandedState() {
async function handleSubmitted(_relationId: string) {
closeOperateModal();
await reloadTreeData();
// 操作完成后恢复树节点的展开状态
await restoreExpandedState();
// 重置标记
isAddFromTreeNode.value = false;
}
/**
* 展开所有子节点(递归)
*
*
* @param tree 树形组件实例
* @param nodes 节点数据数组
*/
@@ -389,7 +389,7 @@ function expandNodes(tree: InstanceType<typeof ElTree>, nodes: Api.SystemManage.
if (treeNode) {
treeNode.expand();
}
// 递归展开子节点
if (node.children && node.children.length > 0) {
expandNodes(tree, node.children);
@@ -399,7 +399,7 @@ function expandNodes(tree: InstanceType<typeof ElTree>, nodes: Api.SystemManage.
/**
* 展开树的前两层节点
*
*
* 只展开根节点和它们的直接子节点,第三层及更深层保持折叠
*/
function expandFirstTwoLevels() {
@@ -414,7 +414,7 @@ function expandFirstTwoLevels() {
if (treeNode) {
treeNode.expand();
}
// 展开第二层(根节点的直接子节点)
if (rootNode.children && rootNode.children.length > 0) {
for (const childNode of rootNode.children) {
@@ -429,12 +429,12 @@ function expandFirstTwoLevels() {
/**
* 恢复树节点的展开状态
*
*
* 根据之前保存的展开状态,恢复对应的节点展开
*/
async function restoreExpandedState() {
await nextTick();
const tree = relationTreeRef.value;
if (!tree || !expandedNodeKeys.value.length) {
return;
@@ -496,7 +496,7 @@ onMounted(async () => {
/>
<!-- 树形卡片区域 -->
<ElCard class="flex-1-hidden card-wrapper min-h-0">
<ElCard class="min-h-0 flex-1-hidden card-wrapper">
<template #header>
<div class="flex items-center justify-between gap-12px">
<div class="flex items-center gap-10px">

View File

@@ -294,7 +294,7 @@ watch(visible, value => {
<BusinessFormDialog
v-model="visible"
:title="title"
preset="md"
preset="sm"
:loading="detailLoading"
:confirm-loading="submitting"
:scrollbar="false"
@@ -302,12 +302,12 @@ watch(visible, value => {
>
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top">
<ElRow :gutter="16">
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem label="上级用户" prop="managerUserId">
<ElSelect
v-model="model.managerUserId"
class="w-full"
placeholder="请选择上级用户"
<ElSelect
v-model="model.managerUserId"
class="w-full"
placeholder="请选择上级用户"
filterable
:disabled="props.operateType === 'add' && props.isAddFromTreeNode"
>
@@ -315,7 +315,7 @@ watch(visible, value => {
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem label="下级用户" prop="subordinateUserId">
<ElSelect
v-model="model.subordinateUserId"
@@ -330,7 +330,7 @@ watch(visible, value => {
</ElCol>
</ElRow>
<ElRow :gutter="16">
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem label="生效开始时间" prop="effectiveFrom" style="width: 100%">
<ElDatePicker
v-model="model.effectiveFrom"
@@ -342,7 +342,7 @@ watch(visible, value => {
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem label="生效结束时间" prop="effectiveUntil" style="width: 100%">
<ElDatePicker
v-model="model.effectiveUntil"

View File

@@ -226,7 +226,7 @@ watch(visible, async value => {
<BusinessFormDialog
v-model="visible"
:title="title"
preset="lg"
preset="md"
:loading="loading"
:confirm-loading="submitting"
max-body-height="70vh"

View File

@@ -160,7 +160,7 @@ watch(visible, async value => {
<BusinessFormDialog
v-model="visible"
:title="title"
preset="md"
preset="sm"
:confirm-loading="submitting"
:scrollbar="false"
@confirm="handleSubmit"
@@ -168,12 +168,12 @@ watch(visible, async value => {
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top">
<BusinessFormSection :title="$t('page.system.user.sections.basicInfo')">
<ElRow :gutter="16">
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.deptName')">
<ElInput :model-value="dept?.name || $t('common.noData')" disabled />
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.candidateUser')" prop="userId">
<ElSelect
v-model="model.userId"
@@ -185,7 +185,7 @@ watch(visible, async value => {
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.effectiveFrom')" prop="effectiveFrom" style="width: 100%">
<ElDatePicker
v-model="model.effectiveFrom"
@@ -197,7 +197,7 @@ watch(visible, async value => {
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.effectiveUntil')" prop="effectiveUntil" style="width: 100%">
<ElDatePicker
v-model="model.effectiveUntil"

View File

@@ -194,7 +194,7 @@ watch(visible, async value => {
<BusinessFormDialog
v-model="visible"
:title="title"
preset="md"
preset="sm"
:confirm-loading="submitting"
:scrollbar="false"
@confirm="handleSubmit"
@@ -219,14 +219,14 @@ watch(visible, async value => {
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.orgTypeLabel')" prop="orgType">
<ElSelect v-model="model.orgType" :placeholder="$t('page.system.user.form.orgTypeLabel')">
<ElOption v-for="item in orgTypeOptions" :key="item.value" :label="$t(item.label)" :value="item.value" />
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.orgCode')" prop="code">
<ElSelect v-if="isCodeSelectable" v-model="model.code" clearable filterable placeholder="请选择组织编码">
<ElOption
@@ -239,7 +239,7 @@ watch(visible, async value => {
<ElInput v-else v-model="model.code" :placeholder="$t('page.system.user.form.orgCode')" />
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.orgSort')" prop="sort">
<ElInputNumber
v-model="model.sort"
@@ -249,7 +249,7 @@ watch(visible, async value => {
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.userStatus')" prop="status">
<ElRadioGroup v-model="model.status" class="business-form-radio-group">
<ElRadio v-for="item in commonStatusOptions" :key="item.value" :value="item.value">

View File

@@ -118,16 +118,17 @@ watch(visible, async value => {
>
<ElForm ref="formRef" :model="model" label-position="top">
<ElRow :gutter="16">
<ElCol :span="12">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.userName')">
<ElInput :model-value="displayUsername" disabled />
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem :label="$t('page.system.user.resignedAt')">
<ElCol :span="24">
<ElFormItem :label="$t('page.system.user.resignedAt')" style="width: 100%">
<ElDatePicker
v-model="model.resignedAt"
class="w-full"
style="width: 100%"
type="datetime"
clearable
:placeholder="$t('page.system.user.form.resignedAt')"

View File

@@ -1,9 +1,7 @@
<script setup lang="ts">
import { SYSTEM_USER_COMPANY_DICT_CODE } from '@/constants/dict';
import { computed } from 'vue';
import { commonStatusOptions } from '@/constants/business';
import { translateOptions } from '@/utils/common';
import DictSelect from '@/components/custom/dict-select.vue';
import TableSearchPanel from '@/components/custom/table-search-panel.vue';
import TableSearchFields from '@/components/custom/table-search-fields.vue';
import { $t } from '@/locales';
defineOptions({ name: 'UserSearch' });
@@ -13,7 +11,7 @@ interface Props {
disabled?: boolean;
}
withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps<Props>(), {
disabled: false
});
@@ -22,81 +20,61 @@ interface Emits {
(e: 'search'): void;
}
defineEmits<Emits>();
const emit = defineEmits<Emits>();
const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required: true });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const fields = computed<any[]>(() => [
{
key: 'nickname',
label: $t('page.system.user.nickName'),
type: 'input',
placeholder: $t('page.system.user.form.nickName')
},
{
key: 'mobile',
label: $t('page.system.user.userPhone'),
type: 'input',
placeholder: $t('page.system.user.form.userPhone')
},
{
key: 'status',
label: $t('page.system.user.userStatus'),
type: 'select',
placeholder: $t('page.system.user.form.userStatus'),
options: commonStatusOptions.map(o => ({
label: $t(o.label as App.I18n.I18nKey),
value: o.value
}))
},
{
key: 'company',
label: '所属公司',
type: 'dict',
dictCode: 'system_user_company',
placeholder: '请选择所属公司'
},
{
key: 'roleId',
label: $t('page.system.user.userRole'),
type: 'select',
placeholder: $t('page.system.user.form.userRole'),
options: props.roleOptions.map(r => ({
label: r.name,
value: r.id
}))
}
]);
</script>
<template>
<TableSearchPanel
:model="model"
<TableSearchFields
v-model="model"
:fields="fields"
:columns="3"
:disabled="disabled"
:action-col-lg="24"
:action-col-md="24"
:action-col-sm="24"
@reset="$emit('reset')"
@search="$emit('search')"
>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.nickName')" prop="nickname">
<ElInput
v-model="model.nickname"
clearable
:disabled="disabled"
:placeholder="$t('page.system.user.form.nickName')"
/>
</ElFormItem>
</ElCol>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userPhone')" prop="mobile">
<ElInput
v-model="model.mobile"
clearable
:disabled="disabled"
:placeholder="$t('page.system.user.form.userPhone')"
/>
</ElFormItem>
</ElCol>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userStatus')" prop="status">
<ElSelect
v-model="model.status"
clearable
:disabled="disabled"
:placeholder="$t('page.system.user.form.userStatus')"
>
<ElOption
v-for="{ label, value } in translateOptions(commonStatusOptions)"
:key="value"
:label="label"
:value="value"
/>
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem label="所属公司" prop="company">
<DictSelect
v-model="model.company"
:dict-code="SYSTEM_USER_COMPANY_DICT_CODE"
filterable
:disabled="disabled"
placeholder="请选择所属公司"
/>
</ElFormItem>
</ElCol>
<ElCol :lg="6" :md="8" :sm="12">
<ElFormItem :label="$t('page.system.user.userRole')" prop="roleId">
<ElSelect
v-model="model.roleId"
clearable
filterable
:disabled="disabled"
:placeholder="$t('page.system.user.form.userRole')"
>
<ElOption v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
</ElSelect>
</ElFormItem>
</ElCol>
</TableSearchPanel>
@search="emit('search')"
@reset="emit('reset')"
/>
</template>