feat(projects): demo 模块适配 Soybean 2.0
This commit is contained in:
@@ -134,6 +134,13 @@ export function useNaivePaginatedTable<ResponseData, ApiData>(
|
||||
}
|
||||
});
|
||||
|
||||
// calculate the total width of the table this is used for horizontal scrolling
|
||||
const scrollX = computed(() => {
|
||||
return result.columns.value.reduce((acc, column) => {
|
||||
return acc + Number(column.width ?? column.minWidth ?? 120);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
async function getDataByPage(page: number = 1) {
|
||||
if (page !== pagination.page) {
|
||||
pagination.page = page;
|
||||
@@ -165,6 +172,7 @@ export function useNaivePaginatedTable<ResponseData, ApiData>(
|
||||
|
||||
return {
|
||||
...result,
|
||||
scrollX,
|
||||
getDataByPage,
|
||||
pagination,
|
||||
mobilePagination
|
||||
@@ -291,6 +299,13 @@ export function useNaiveTreeTable<ResponseData, ApiData>(options: UseNaiveTreeTa
|
||||
getColumns
|
||||
});
|
||||
|
||||
// calculate the total width of the table this is used for horizontal scrolling
|
||||
const scrollX = computed(() => {
|
||||
return result.columns.value.reduce((acc, column) => {
|
||||
return acc + Number(column.width ?? column.minWidth ?? 120);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
const { keyField = 'id', defaultExpandAll = false } = options;
|
||||
|
||||
const expandedRowKeys = ref<ApiData[keyof ApiData][]>([]);
|
||||
@@ -323,6 +338,7 @@ export function useNaiveTreeTable<ResponseData, ApiData>(options: UseNaiveTreeTa
|
||||
|
||||
return {
|
||||
...result,
|
||||
scrollX,
|
||||
rows,
|
||||
isCollapse,
|
||||
expandedRowKeys,
|
||||
|
||||
Vendored
+8
@@ -36,8 +36,10 @@ declare module 'vue' {
|
||||
IconLocalLogo: typeof import('~icons/local/logo')['default']
|
||||
IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
||||
IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
|
||||
IconMdiGithub: typeof import('~icons/mdi/github')['default']
|
||||
IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||
IconSimpleIconsGitee: typeof import('~icons/simple-icons/gitee')['default']
|
||||
IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
|
||||
IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||
JsonPreview: typeof import('./../components/custom/json-preview.vue')['default']
|
||||
@@ -64,6 +66,8 @@ declare module 'vue' {
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||
NForm: typeof import('naive-ui')['NForm']
|
||||
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
NGi: typeof import('naive-ui')['NGi']
|
||||
NGrid: typeof import('naive-ui')['NGrid']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
@@ -139,8 +143,10 @@ declare global {
|
||||
const IconLocalLogo: typeof import('~icons/local/logo')['default']
|
||||
const IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
|
||||
const IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
|
||||
const IconMdiGithub: typeof import('~icons/mdi/github')['default']
|
||||
const IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||
const IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||
const IconSimpleIconsGitee: typeof import('~icons/simple-icons/gitee')['default']
|
||||
const IconTooltip: typeof import('./../components/common/icon-tooltip.vue')['default']
|
||||
const IconUilSearch: typeof import('~icons/uil/search')['default']
|
||||
const JsonPreview: typeof import('./../components/custom/json-preview.vue')['default']
|
||||
@@ -167,6 +173,8 @@ declare global {
|
||||
const NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
const NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||
const NEmpty: typeof import('naive-ui')['NEmpty']
|
||||
const NForm: typeof import('naive-ui')['NForm']
|
||||
const NFormItem: typeof import('naive-ui')['NFormItem']
|
||||
const NGi: typeof import('naive-ui')['NGi']
|
||||
const NGrid: typeof import('naive-ui')['NGrid']
|
||||
const NInput: typeof import('naive-ui')['NInput']
|
||||
|
||||
@@ -187,13 +187,13 @@ async function handleSocialLogin(type: Api.System.SocialSource) {
|
||||
<div class="w-full flex-y-center gap-16px">
|
||||
<NButton class="flex-1" @click="handleSocialLogin('gitee')">
|
||||
<template #icon>
|
||||
<icon-simple-icons:gitee class="color-#c71d23" />
|
||||
<icon-simple-icons-gitee class="color-#c71d23" />
|
||||
</template>
|
||||
<span class="ml-6px">Gitee</span>
|
||||
</NButton>
|
||||
<NButton class="flex-1" @click="handleSocialLogin('github')">
|
||||
<template #icon>
|
||||
<icon-mdi:github class="color-#010409" />
|
||||
<icon-mdi-github class="color-#010409" />
|
||||
</template>
|
||||
<span class="ml-6px">GitHub</span>
|
||||
</NButton>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { NDivider } from 'naive-ui';
|
||||
import { fetchBatchDeleteDemo, fetchGetDemoList } from '@/service/api/demo';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
@@ -19,7 +19,7 @@ const appStore = useAppStore();
|
||||
const { download } = useDownload();
|
||||
const { hasAuth } = useAuth();
|
||||
|
||||
const searchParams: Api.Demo.DemoSearchParams = reactive({
|
||||
const searchParams = ref<Api.Demo.DemoSearchParams>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deptId: null,
|
||||
@@ -30,12 +30,13 @@ const searchParams: Api.Demo.DemoSearchParams = reactive({
|
||||
params: {}
|
||||
});
|
||||
|
||||
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination } = useNaivePaginatedTable({
|
||||
api: () => fetchGetDemoList(searchParams),
|
||||
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
|
||||
useNaivePaginatedTable({
|
||||
api: () => fetchGetDemoList(searchParams.value),
|
||||
transform: response => defaultTransform(response),
|
||||
onPaginationParamsChange: params => {
|
||||
searchParams.pageSize = params.page;
|
||||
searchParams.pageNum = params.pageSize;
|
||||
searchParams.value.pageNum = params.page;
|
||||
searchParams.value.pageSize = params.pageSize;
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
@@ -133,7 +134,7 @@ const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagi
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
|
||||
useTableOperate(data, 'id', getData);
|
||||
@@ -163,7 +164,7 @@ async function handleExport() {
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<DemoSearch v-model:model="searchParams" @search="getDataByPage" />
|
||||
<DemoSearch v-model:model="searchParams" @reset="getDataByPage" @search="getDataByPage" />
|
||||
<NCard title="测试单表列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation
|
||||
@@ -184,7 +185,7 @@ async function handleExport() {
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:flex-height="!appStore.isMobile"
|
||||
:scroll-x="962"
|
||||
:scroll-x="scrollX"
|
||||
:loading="loading"
|
||||
remote
|
||||
:row-key="row => row.id"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { fetchCreateDemo, fetchUpdateDemo } from '@/service/api/demo/demo';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
@@ -40,7 +41,7 @@ const title = computed(() => {
|
||||
|
||||
type Model = Api.Demo.DemoOperateParams;
|
||||
|
||||
const model: Model = reactive(createDefaultModel());
|
||||
const model = ref<Model>(createDefaultModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
@@ -65,13 +66,10 @@ const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
};
|
||||
|
||||
function handleUpdateModelWhenEdit() {
|
||||
if (props.operateType === 'add') {
|
||||
Object.assign(model, createDefaultModel());
|
||||
return;
|
||||
}
|
||||
model.value = createDefaultModel();
|
||||
|
||||
if (props.operateType === 'edit' && props.rowData) {
|
||||
Object.assign(model, props.rowData);
|
||||
Object.assign(model.value, jsonClone(props.rowData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,15 +80,15 @@ function closeDrawer() {
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
|
||||
const { id, deptId, userId, orderNum, testKey, value } = model.value;
|
||||
|
||||
// request
|
||||
if (props.operateType === 'add') {
|
||||
const { deptId, userId, orderNum, testKey, value } = model;
|
||||
const { error } = await fetchCreateDemo({ deptId, userId, orderNum, testKey, value });
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit') {
|
||||
const { id, deptId, userId, orderNum, testKey, value } = model;
|
||||
const { error } = await fetchUpdateDemo({ id, deptId, userId, orderNum, testKey, value });
|
||||
if (error) return;
|
||||
}
|
||||
@@ -125,7 +123,7 @@ watch(visible, () => {
|
||||
<NInput v-model:value="model.testKey" placeholder="请输入 key 键" />
|
||||
</NFormItem>
|
||||
<NFormItem label="值" path="value">
|
||||
<OssUpload v-model:value="model.value as string" upload-type="image" placeholder="请输入值" />
|
||||
<NInput v-model:value="model.value" placeholder="请输入值" />
|
||||
</NFormItem>
|
||||
<NFormItem label="备注" path="remark">
|
||||
<NInput v-model:value="model.remark" type="textarea" placeholder="请输入备注" />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { toRaw } from 'vue';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
@@ -7,6 +9,7 @@ defineOptions({
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
@@ -16,22 +19,16 @@ const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
|
||||
const model = defineModel<Api.Demo.DemoSearchParams>('model', { required: true });
|
||||
|
||||
const defaultModel = jsonClone(toRaw(model.value));
|
||||
|
||||
function resetModel() {
|
||||
model.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deptId: null,
|
||||
userId: null,
|
||||
orderNum: null,
|
||||
testKey: null,
|
||||
value: null,
|
||||
params: {}
|
||||
};
|
||||
Object.assign(model.value, defaultModel);
|
||||
}
|
||||
|
||||
async function reset() {
|
||||
await restoreValidation();
|
||||
resetModel();
|
||||
emit('reset');
|
||||
}
|
||||
|
||||
async function search() {
|
||||
@@ -46,16 +43,16 @@ async function search() {
|
||||
<NCollapseItem :title="$t('common.search')" name="user-search">
|
||||
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24 s:12 m:6" label="部门" path="deptId" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="部门" path="deptId" class="pr-24px" label-width="auto">
|
||||
<DeptTreeSelect v-model:value="model.deptId" placeholder="请选择部门" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="用户" path="userId" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="用户" path="userId" class="pr-24px" label-width="auto">
|
||||
<UserSelect v-model:value="model.userId" placeholder="请选择用户" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="key 键" path="testKey" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="key 键" path="testKey" class="pr-24px" label-width="auto">
|
||||
<NInput v-model:value="model.testKey" placeholder="请输入 key 键" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="值" path="value" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="值" path="value" class="pr-24px" label-width="auto">
|
||||
<NInput v-model:value="model.value" placeholder="请输入值" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :show-feedback="false" span="24" class="pr-24px">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { NDivider } from 'naive-ui';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { fetchBatchDeleteTree, fetchGetTreeList } from '@/service/api/demo/tree';
|
||||
@@ -20,9 +20,7 @@ const appStore = useAppStore();
|
||||
const { download } = useDownload();
|
||||
const { hasAuth } = useAuth();
|
||||
|
||||
const searchParams: Api.Demo.TreeSearchParams = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
const searchParams = ref<Api.Demo.TreeSearchParams>({
|
||||
parentId: null,
|
||||
deptId: null,
|
||||
userId: null,
|
||||
@@ -30,10 +28,21 @@ const searchParams: Api.Demo.TreeSearchParams = reactive({
|
||||
params: {}
|
||||
});
|
||||
|
||||
const { columns, columnChecks, data, rows, getData, loading, expandedRowKeys, isCollapse, expandAll, collapseAll } =
|
||||
useNaiveTreeTable({
|
||||
const {
|
||||
columns,
|
||||
columnChecks,
|
||||
data,
|
||||
rows,
|
||||
getData,
|
||||
loading,
|
||||
expandedRowKeys,
|
||||
isCollapse,
|
||||
expandAll,
|
||||
collapseAll,
|
||||
scrollX
|
||||
} = useNaiveTreeTable({
|
||||
keyField: 'id',
|
||||
api: fetchGetTreeList,
|
||||
api: () => fetchGetTreeList(searchParams.value),
|
||||
transform: response => treeTransform(response, { idField: 'id' }),
|
||||
columns: () => [
|
||||
{
|
||||
@@ -132,7 +141,7 @@ const { columns, columnChecks, data, rows, getData, loading, expandedRowKeys, is
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
|
||||
useTableOperate(rows, 'id', getData);
|
||||
@@ -167,7 +176,7 @@ function handleExport() {
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<TreeSearch v-model:model="searchParams" :tree-list="data" @search="getData" />
|
||||
<TreeSearch v-model:model="searchParams" :tree-list="data" @reset="getData" @search="getData" />
|
||||
<NCard title="测试树列表" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation
|
||||
@@ -204,7 +213,7 @@ function handleExport() {
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:flex-height="!appStore.isMobile"
|
||||
:scroll-x="962"
|
||||
:scroll-x="scrollX"
|
||||
:loading="loading"
|
||||
remote
|
||||
:row-key="row => row.id"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { fetchCreateTree, fetchUpdateTree } from '@/service/api/demo/tree';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
@@ -42,7 +43,7 @@ const title = computed(() => {
|
||||
|
||||
type Model = Api.Demo.TreeOperateParams;
|
||||
|
||||
const model: Model = reactive(createDefaultModel());
|
||||
const model = ref<Model>(createDefaultModel());
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
@@ -64,14 +65,11 @@ const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
};
|
||||
|
||||
function handleUpdateModelWhenEdit() {
|
||||
if (props.operateType === 'add') {
|
||||
Object.assign(model, createDefaultModel());
|
||||
model.parentId = props.rowData?.id || 0;
|
||||
return;
|
||||
}
|
||||
model.value = createDefaultModel();
|
||||
model.value.parentId = props.rowData?.id || 0;
|
||||
|
||||
if (props.operateType === 'edit' && props.rowData) {
|
||||
Object.assign(model, props.rowData);
|
||||
Object.assign(model.value, jsonClone(props.rowData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,15 +80,15 @@ function closeDrawer() {
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
|
||||
const { id, parentId, deptId, userId, treeName } = model.value;
|
||||
|
||||
// request
|
||||
if (props.operateType === 'add') {
|
||||
const { parentId, deptId, userId, treeName } = model;
|
||||
const { error } = await fetchCreateTree({ parentId, deptId, userId, treeName });
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
if (props.operateType === 'edit') {
|
||||
const { id, parentId, deptId, userId, treeName } = model;
|
||||
const { error } = await fetchUpdateTree({ id, parentId, deptId, userId, treeName });
|
||||
if (error) return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { toRaw } from 'vue';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
@@ -14,6 +16,7 @@ interface Props {
|
||||
defineProps<Props>();
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
@@ -23,21 +26,16 @@ const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
|
||||
const model = defineModel<Api.Demo.TreeSearchParams>('model', { required: true });
|
||||
|
||||
const defaultModel = jsonClone(toRaw(model.value));
|
||||
|
||||
function resetModel() {
|
||||
model.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
parentId: null,
|
||||
deptId: null,
|
||||
userId: null,
|
||||
treeName: null,
|
||||
params: {}
|
||||
};
|
||||
Object.assign(model.value, defaultModel);
|
||||
}
|
||||
|
||||
async function reset() {
|
||||
await restoreValidation();
|
||||
resetModel();
|
||||
emit('reset');
|
||||
}
|
||||
|
||||
async function search() {
|
||||
@@ -52,7 +50,7 @@ async function search() {
|
||||
<NCollapseItem :title="$t('common.search')" name="user-search">
|
||||
<NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24 s:12 m:6" label="父 ID" path="parentId" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="父 ID" path="parentId" class="pr-24px" label-width="auto">
|
||||
<NTreeSelect
|
||||
v-model:value="model.parentId"
|
||||
filterable
|
||||
@@ -63,13 +61,13 @@ async function search() {
|
||||
:default-expanded-keys="[0]"
|
||||
/>
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="部门" path="deptId" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="部门" path="deptId" class="pr-24px" label-width="auto">
|
||||
<DeptTreeSelect v-model:value="model.deptId" placeholder="请选择部门" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="用户" path="userId" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="用户" path="userId" class="pr-24px" label-width="auto">
|
||||
<UserSelect v-model:value="model.userId" placeholder="请选择用户" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" label="值" path="treeName" class="pr-24px">
|
||||
<NFormItemGi span="24 s:12 m:6" label="值" path="treeName" class="pr-24px" label-width="auto">
|
||||
<NInput v-model:value="model.treeName" placeholder="请输入值" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi :show-feedback="false" span="24" class="pr-24px">
|
||||
|
||||
Reference in New Issue
Block a user