diff --git a/mock/table/index.ts b/mock/table/index.ts index f06f7f53a..8caee837a 100644 --- a/mock/table/index.ts +++ b/mock/table/index.ts @@ -92,5 +92,46 @@ export default [ } } } + }, + // 详情接口 + { + url: '/example/detail', + method: 'get', + response: ({ query }) => { + const { id } = query + for (const example of List) { + if (example.id === id) { + return { + code: result_code, + data: example + } + } + } + } + }, + // 删除接口 + { + url: '/example/delete', + method: 'post', + response: ({ body }) => { + const ids = body.ids + if (!ids) { + return { + code: '500', + message: '请选择需要删除的数据' + } + } else { + let i = List.length + while (i--) { + if (ids.indexOf(List[i].id) !== -1) { + List.splice(i, 1) + } + } + return { + code: result_code, + data: 'success' + } + } + } } ] as MockMethod[] diff --git a/public/favicon.ico b/public/favicon.ico index df8350595..5a7de0826 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/logo.png b/public/logo.png index 44be9a8ec..7e5002b3e 100644 Binary files a/public/logo.png and b/public/logo.png differ diff --git a/src/api/table/index.ts b/src/api/table/index.ts index ce0f6858c..294659f7f 100644 --- a/src/api/table/index.ts +++ b/src/api/table/index.ts @@ -10,6 +10,28 @@ export const getTableListApi = ({ params }: AxiosConfig) => { }>({ url: '/example/list', method: 'get', params }) } -export const saveTableApi = ({ data }: AxiosConfig) => { +export const saveTableApi = ({ data }: AxiosConfig) => { return request({ url: '/example/save', method: 'post', data }) } + +export const getTableDetApi = ({ + params +}: AxiosConfig< + { + id: string + }, + Recordable +>) => { + return request({ url: '/example/detail', method: 'get', params }) +} + +export const delTableListApi = ({ + data +}: AxiosConfig< + Recordable, + { + id: string[] | number[] + } +>) => { + return request({ url: '/example/delete', method: 'post', data }) +} diff --git a/src/assets/imgs/avatar.png b/src/assets/imgs/avatar.png deleted file mode 100644 index e16488e45..000000000 Binary files a/src/assets/imgs/avatar.png and /dev/null differ diff --git a/src/assets/imgs/logo.png b/src/assets/imgs/logo.png index 44be9a8ec..7e5002b3e 100644 Binary files a/src/assets/imgs/logo.png and b/src/assets/imgs/logo.png differ diff --git a/src/components/Descriptions/src/Descriptions.vue b/src/components/Descriptions/src/Descriptions.vue index b68cd5049..7e985bd83 100644 --- a/src/components/Descriptions/src/Descriptions.vue +++ b/src/components/Descriptions/src/Descriptions.vue @@ -100,7 +100,7 @@ const toggleClick = () => { diff --git a/src/components/Table/index.ts b/src/components/Table/index.ts index af647af99..59847e934 100644 --- a/src/components/Table/index.ts +++ b/src/components/Table/index.ts @@ -3,6 +3,7 @@ import Table from './src/Table.vue' export interface TableExpose { setProps: (props: Recordable) => void setColumn: (columnProps: TableSetPropsType[]) => void + selections: Recordable[] } export { Table } diff --git a/src/components/Table/src/Table.vue b/src/components/Table/src/Table.vue index 5dd850ef6..6e22dfa23 100644 --- a/src/components/Table/src/Table.vue +++ b/src/components/Table/src/Table.vue @@ -89,9 +89,16 @@ export default defineComponent({ } } + const selections = ref([]) + + const selectionChange = (selection: Recordable[]) => { + selections.value = selection + } + expose({ setProps, - setColumn + setColumn, + selections }) const pagination = computed(() => { @@ -226,7 +233,7 @@ export default defineComponent({ align={v.align || align} headerAlign={v.headerAlign || headerAlign} label={v.label} - width="100px" + width="65px" > ) } else { @@ -264,6 +271,7 @@ export default defineComponent({ // @ts-ignore ref={elTableRef} data={unref(getProps).data} + onSelection-change={selectionChange} {...getBindValue} > {{ diff --git a/src/hooks/web/useTable.ts b/src/hooks/web/useTable.ts index 4be92df85..2c32399c2 100644 --- a/src/hooks/web/useTable.ts +++ b/src/hooks/web/useTable.ts @@ -1,12 +1,16 @@ import { Table, TableExpose } from '@/components/Table' -import { ElTable } from 'element-plus' +import { ElTable, ElMessageBox, ElMessage } from 'element-plus' import { ref, reactive, watch, computed, unref, nextTick } from 'vue' import { AxiosPromise } from 'axios' import { get, assign } from 'lodash-es' import type { TableProps } from '@/components/Table/src/types' +import { useI18n } from '@/hooks/web/useI18n' + +const { t } = useI18n() interface UseTableConfig { getListApi: (option: L) => AxiosPromise + delListApi?: (option: AxiosConfig) => AxiosPromise // 返回数据格式配置 response: { list: string @@ -22,7 +26,6 @@ interface TableObject { tableList: K[] parmasObj: L loading: boolean - dialogVisible: boolean currentRow: Nullable } @@ -42,8 +45,6 @@ export const useTable = ( parmasObj: {} as L, // 加载中 loading: true, - // 弹窗 - dialogVisible: false, // 当前行的数据 currentRow: null }) @@ -95,11 +96,31 @@ export const useTable = ( return table } + const delData = async (paramsObj: AxiosConfig, ids: string[] | number[]) => { + const res = await (config?.delListApi && config?.delListApi(paramsObj)) + if (res) { + ElMessage.success(t('common.delSuccess')) + + // 计算出临界点 + const currentPage = + tableObject.total % tableObject.pageSize === ids.length || tableObject.pageSize === 1 + ? tableObject.currentPage > 1 + ? tableObject.currentPage - 1 + : tableObject.currentPage + : tableObject.currentPage + + tableObject.currentPage = currentPage + methods.getList() + } + } + const methods: { setProps: (props: Recordable) => void getList: () => Promise setColumn: (columnProps: TableSetPropsType[]) => void setSearchParmas: (data: Recordable) => void + getSelections: () => Promise + delList: (ids: string[] | number[], multiple: boolean, message?: boolean) => Promise } = { getList: async () => { tableObject.loading = true @@ -122,6 +143,10 @@ export const useTable = ( const table = await getTable() table?.setColumn(columnProps) }, + getSelections: async () => { + const table = await getTable() + return (table?.selections || []) as K[] + }, // 与Search组件结合 setSearchParmas: (data: Recordable) => { tableObject.currentPage = 1 @@ -133,6 +158,39 @@ export const useTable = ( } }) methods.getList() + }, + // 删除数据 + delList: async (ids: string[] | number[], multiple: boolean, message = true) => { + const tableRef = await getTable() + if (multiple) { + if (!tableRef?.selections.length) { + ElMessage.warning(t('common.delNoData')) + return + } + } else { + if (!tableObject.currentRow) { + ElMessage.warning(t('common.delNoData')) + return + } + } + const paramsObj: AxiosConfig = { + data: { + ids + } + } + if (message) { + ElMessageBox.confirm(t('common.delMessage'), t('common.delWarning'), { + confirmButtonText: t('common.delOk'), + cancelButtonText: t('common.delCancel'), + type: 'warning' + }) + .then(async () => { + await delData(paramsObj, ids) + }) + .catch(() => {}) + } else { + await delData(paramsObj, ids) + } } } diff --git a/src/locales/en.ts b/src/locales/en.ts index 2a57b79ac..b443dbd87 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -33,7 +33,13 @@ export default { query: 'Query', reset: 'Reset', shrink: 'Put away', - expand: 'Expand' + expand: 'Expand', + delMessage: 'Delete the selected data?', + delWarning: 'Warning', + delOk: 'OK', + delCancel: 'Cancel', + delNoData: 'Please select the data to delete', + delSuccess: 'Deleted successfully' }, setting: { projectSetting: 'Project setting', @@ -374,6 +380,7 @@ export default { pageviews: 'Pageviews', important: 'Important', content: 'Content', - save: 'Save' + save: 'Save', + detail: 'Detail' } } diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 2f6ecb0de..a23e9bee2 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -33,7 +33,13 @@ export default { query: '查询', reset: '重置', shrink: '收起', - expand: '展开' + expand: '展开', + delMessage: '是否删除所选中数据?', + delWarning: '提示', + delOk: '确定', + delCancel: '取消', + delNoData: '请选择需要删除的数据', + delSuccess: '删除成功' }, setting: { projectSetting: '项目配置', @@ -371,6 +377,7 @@ export default { pageviews: '阅读数', important: '重要', content: '内容', - save: '保存' + save: '保存', + detail: '详情' } } diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index be5f7f058..c88cb5093 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -1,10 +1,13 @@ import { defineStore } from 'pinia' import { store } from '../index' +import { useCache } from '@/hooks/web/useCache' import { appModules } from '@/config/app' import type { AppState, LayoutType, ThemeTypes } from '@/config/app' import { setCssVar, humpToUnderline } from '@/utils' import { ElMessage } from 'element-plus' +const { wsCache } = useCache() + export const useAppStore = defineStore({ id: 'app', state: (): AppState => appModules, @@ -119,6 +122,7 @@ export const useAppStore = defineStore({ return } this.layout = layout + wsCache.set('layout', this.layout) }, setTitle(title: string) { this.title = title @@ -132,15 +136,18 @@ export const useAppStore = defineStore({ document.documentElement.classList.add('light') document.documentElement.classList.remove('dark') } + wsCache.set('isDark', this.isDark) }, setCurrentSize(currentSize: ElememtPlusSzie) { this.currentSize = currentSize + wsCache.set('currentSize', this.currentSize) }, setMobile(mobile: boolean) { this.mobile = mobile }, setTheme(theme: ThemeTypes) { this.theme = Object.assign(this.theme, theme) + wsCache.set('theme', this.theme) }, setCssVarTheme() { for (const key in this.theme) { diff --git a/src/store/modules/locale.ts b/src/store/modules/locale.ts index 203bc33ee..4b7d0640c 100644 --- a/src/store/modules/locale.ts +++ b/src/store/modules/locale.ts @@ -1,8 +1,11 @@ import { defineStore } from 'pinia' import { store } from '../index' +import { useCache } from '@/hooks/web/useCache' import { localeModules, elLocaleMap } from '@/config/locale' import type { LocaleState } from '@/config/locale' +const { wsCache } = useCache() + export const useLocaleStore = defineStore({ id: 'locales', state: (): LocaleState => localeModules, @@ -22,6 +25,7 @@ export const useLocaleStore = defineStore({ // this.locale = Object.assign(this.locale, localeMap) this.currentLocale.lang = localeMap?.lang this.currentLocale.elLocale = elLocaleMap[localeMap?.lang] + wsCache.set('lang', localeMap?.lang) } } }) diff --git a/src/views/Example/Dialog/ExampleDialog.vue b/src/views/Example/Dialog/ExampleDialog.vue index bbce70e00..4e984983f 100644 --- a/src/views/Example/Dialog/ExampleDialog.vue +++ b/src/views/Example/Dialog/ExampleDialog.vue @@ -5,11 +5,12 @@ import { Dialog } from '@/components/Dialog' import { useI18n } from '@/hooks/web/useI18n' import { ElButton, ElTag } from 'element-plus' import { Table } from '@/components/Table' -import { getTableListApi, saveTableApi } from '@/api/table' +import { getTableListApi, saveTableApi, delTableListApi } from '@/api/table' import { useTable } from '@/hooks/web/useTable' import { TableData } from '@/api/table/types' import { h, reactive, ref, unref } from 'vue' import Write from './components/Write.vue' +import Detail from './components/Detail.vue' const { register, tableObject, methods } = useTable< { @@ -19,6 +20,7 @@ const { register, tableObject, methods } = useTable< TableData >({ getListApi: getTableListApi, + delListApi: delTableListApi, response: { list: 'list', total: 'total' @@ -82,18 +84,43 @@ const columns = reactive([ }, { field: 'action', + width: '260px', label: t('tableDemo.action') } ]) +const dialogVisible = ref(false) + +const dialogTitle = ref('') + const AddAction = () => { + dialogTitle.value = t('exampleDemo.add') tableObject.currentRow = null - tableObject.dialogVisible = true + dialogVisible.value = true } -const editAction = (row: TableData) => { +const delLoading = ref(false) + +const delData = async (row: TableData | null, multiple: boolean) => { tableObject.currentRow = row - tableObject.dialogVisible = true + const { delList, getSelections } = methods + const selections = await getSelections() + delLoading.value = true + await delList( + multiple ? selections.map((v) => v.id) : [tableObject.currentRow?.id as string], + multiple + ).finally(() => { + delLoading.value = false + }) +} + +const actionType = ref('') + +const action = (row: TableData, type: string) => { + dialogTitle.value = t(type === 'edit' ? 'exampleDemo.edit' : 'exampleDemo.detail') + actionType.value = type + tableObject.currentRow = row + dialogVisible.value = true } const writeRef = ref>() @@ -105,7 +132,7 @@ const save = async () => { const validate = await write?.elFormRef?.validate()?.catch(() => {}) if (validate) { loading.value = true - const data = await write?.getFormData() + const data = (await write?.getFormData()) as TableData const res = await saveTableApi({ data }) @@ -114,7 +141,7 @@ const save = async () => { loading.value = false }) if (res) { - tableObject.dialogVisible = false + dialogVisible.value = false tableObject.currentPage = 1 getList() } @@ -128,7 +155,9 @@ const save = async () => {
{{ t('exampleDemo.add') }} - {{ t('exampleDemo.del') }} + + {{ t('exampleDemo.del') }} +
{ @register="register" >
- - + + + + diff --git a/src/views/Example/Dialog/components/Detail.vue b/src/views/Example/Dialog/components/Detail.vue new file mode 100644 index 000000000..4da0a99ac --- /dev/null +++ b/src/views/Example/Dialog/components/Detail.vue @@ -0,0 +1,95 @@ + + +