diff --git a/locales/en-US.json b/locales/en-US.json index 1eac2219..8d8c5bfe 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -6,7 +6,8 @@ "Error": "Error Page", "Echart": "Chart", "scrollReveal": "Scroll Reveal", - "Axios": "Axios Request" + "Axios": "Axios Request", + "Table": "Table" }, "LayoutHeaderTooltipOptions": { "Reload": "Reload Current Page", diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 988a7d39..6a68e52c 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -6,7 +6,8 @@ "Error": "错误页", "Echart": "可视化", "scrollReveal": "滚动动画", - "Axios": "请求" + "Axios": "请求", + "Table": "表格" }, "LayoutHeaderTooltipOptions": { "Reload": "刷新当前页面", diff --git a/package.json b/package.json index 0bf7f942..151e1bd1 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "screenfull": "^6.0.2", "vue": "^3.2.37", "vue-i18n": "^9.2.2", - "vue-router": "^4.1.3" + "vue-router": "^4.1.3", + "vuedraggable": "^4.1.0" }, "devDependencies": { "@babel/core": "^7.20.2", diff --git a/src/components/RayGlobalProvider/index.tsx b/src/components/RayGlobalProvider/index.tsx index 7931ea8c..fe782fb5 100644 --- a/src/components/RayGlobalProvider/index.tsx +++ b/src/components/RayGlobalProvider/index.tsx @@ -21,6 +21,7 @@ const GlobalProvider = defineComponent({ const modelThemeValue = computed(() => settingStore.themeValue ? darkTheme : null, ) + const modelLocal = computed(() => settingStore.naiveLocal) const { message, notification, dialog, loadingBar } = createDiscreteApi( ['message', 'dialog', 'notification', 'loadingBar'], @@ -39,6 +40,7 @@ const GlobalProvider = defineComponent({ return { modelPrimaryColorOverride, modelThemeValue, + modelLocal, } }, render() { @@ -46,6 +48,8 @@ const GlobalProvider = defineComponent({ diff --git a/src/components/RayTable/index.ts b/src/components/RayTable/index.ts new file mode 100644 index 00000000..9235f502 --- /dev/null +++ b/src/components/RayTable/index.ts @@ -0,0 +1,4 @@ +import RayTable from './src/index' + +export * as Table from './src/type' +export default RayTable diff --git a/src/components/RayTable/src/components/TableSetting/index.tsx b/src/components/RayTable/src/components/TableSetting/index.tsx new file mode 100644 index 00000000..aa1acd4f --- /dev/null +++ b/src/components/RayTable/src/components/TableSetting/index.tsx @@ -0,0 +1,24 @@ +/** + * + * @author Ray + * + * @date 2022-12-08 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import RayIcon from '@/components/RayIcon/index' + +const TableSetting = defineComponent({ + name: 'TableSetting', + setup() { + return {} + }, + render() { + return <> + }, +}) + +export default TableSetting diff --git a/src/components/RayTable/src/index.scss b/src/components/RayTable/src/index.scss new file mode 100644 index 00000000..b63d08e4 --- /dev/null +++ b/src/components/RayTable/src/index.scss @@ -0,0 +1,5 @@ +.ray-table__setting { + cursor: pointer; + outline: none; + border: none; +} diff --git a/src/components/RayTable/src/index.tsx b/src/components/RayTable/src/index.tsx new file mode 100644 index 00000000..02cce7e5 --- /dev/null +++ b/src/components/RayTable/src/index.tsx @@ -0,0 +1,55 @@ +/** + * + * @author Ray + * + * @date 2022-12-08 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import './index.scss' +import { NDataTable, NCard } from 'naive-ui' +import props from './props' +import RayIcon from '@/components/RayIcon/index' + +const RayTable = defineComponent({ + name: 'RayTable', + props: props, + setup(props) { + const modelRightClickMenu = computed(() => props.rightClickMenu) + + provide('rayTableProvider', { + modelRightClickMenu, + }) + + return {} + }, + render() { + return ( + + {{ + default: () => ( + + {{ + empty: () => this.$slots?.empty, + loading: () => this.$slots?.loading, + }} + + ), + header: () => this.title, + 'header-extra': () => ( + + ), + }} + + ) + }, +}) + +export default RayTable diff --git a/src/components/RayTable/src/props.ts b/src/components/RayTable/src/props.ts new file mode 100644 index 00000000..8ca2ec24 --- /dev/null +++ b/src/components/RayTable/src/props.ts @@ -0,0 +1,70 @@ +/** + * + * @author Ray + * + * @date 2022-12-08 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { dataTableProps } from 'naive-ui' + +import type { PropType, VNode } from 'vue' +import type { DropdownMixedOption } from './type' + +const rayTableProps = { + ...dataTableProps, // 继承 `data table props` + rightClickMenu: { + /** + * + * 表格右键菜单, 基于 `NDropdown` 实现 + * + * 如果菜单内容长度为 `0` 则不会渲染 + * + * 只需要传入对应的菜单配置项, 即可自动开启右键菜单功能 + */ + type: Array as PropType, + default: () => [], + }, + title: { + /** + * + * 表格标题 + * + * 可以自定义渲染 + */ + type: String, + default: '', + }, + action: { + /** + * + * 是否开启操作栏 + * + * 默认开启 + */ + type: Boolean, + default: true, + }, + actionExtra: { + /** + * + * 自定义拓展操作栏 + * + * 暂时不开放 + */ + type: Object as PropType, + default: () => ({}), + }, +} as const + +export default rayTableProps + +/** + * + * `Ray Table Props` + * + * 继承 `naive ui Data Table` + */ diff --git a/src/components/RayTable/src/type.ts b/src/components/RayTable/src/type.ts new file mode 100644 index 00000000..e30c1fcf --- /dev/null +++ b/src/components/RayTable/src/type.ts @@ -0,0 +1,15 @@ +import type { + DropdownOption, + DropdownGroupOption, + DropdownDividerOption, + DropdownRenderOption, + DataTableColumns, +} from 'naive-ui' + +export interface ActionOptions extends DataTableColumns {} + +export type DropdownMixedOption = + | DropdownOption + | DropdownGroupOption + | DropdownDividerOption + | DropdownRenderOption diff --git a/src/icons/table.svg b/src/icons/table.svg new file mode 100644 index 00000000..81b761a0 --- /dev/null +++ b/src/icons/table.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/language/index.ts b/src/language/index.ts index 960407b8..50025e4c 100644 --- a/src/language/index.ts +++ b/src/language/index.ts @@ -1,18 +1,43 @@ +/** + * + * @author Ray + * + * @date 2022-12-08 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + import { createI18n } from 'vue-i18n' import messages from '@intlify/unplugin-vue-i18n/messages' // 导入所有语言包 +import { zhCN, dateZhCN } from 'naive-ui' // 导入 `naive ui` 中文包 +import { enUS, dateEnUS } from 'naive-ui' // 导入 `naive ui` 英文包 import { getCache } from '@use-utils/cache' import type { App } from 'vue' -export const setupI18n = (app: App) => { - const _locales: string = +/** + * + * @returns 获取当前环境默认语言 + * + * @remak 未避免出现加载语言错误问题, 故而在 `main.ts` 注册时, 应优先加载 `i18n` 避免出现该问题 + */ +export const useDefaultLocal = () => { + const locale: string = getCache('localeLanguage', 'localStorage') !== 'no' ? getCache('localeLanguage', 'localStorage') : 'zh-CN' + return locale +} + +export const setupI18n = (app: App) => { + const locale = useDefaultLocal() + const i18n = createI18n({ - locale: _locales, + locale, allowComposition: true, messages, }) @@ -33,8 +58,54 @@ export const useLanguageOptions = () => [ /** * - * 注册 `vue-i18n` - * 注意: 每次修改 `locales` 中的文件后, 需要重启项目 - * 预设 `localeLanguage` 作为缓存 `key` - * 预设中文作为基础语言 + * @param key 切换对应语言 + * @returns 组件库对应语言包 + * + * @remark 受打包体积影响. 如果有新的语言添加, 则需要手动引入对应语言包(https://www.naiveui.com/zh-CN/dark/docs/i18n) + */ +export const useNaiveLocal = (key: string) => { + switch (key) { + case 'zh-CN': + return { + local: zhCN, + dateLocal: dateZhCN, + } + + case 'en-US': + return { + local: enUS, + dateLocal: dateEnUS, + } + + default: + return { + local: zhCN, + dateLocal: dateZhCN, + } + } +} + +/** + * + * @returns 当前环境语言组件库语言包 + * + * @remark 获取默认语言包 + */ +export const useDefaultNaiveLocal = () => { + const local = useDefaultLocal() + + return useNaiveLocal(local) +} + +/** + * + * 注册 `vue-i18n` + * + * 注意: 因使用 `i18n` 提供虚拟文件注入缘故, 每次修改 `locales` 中的文件后, 需要重启项目 + * + * 预设 `localeLanguage` 作为缓存 `key` + * + * 预设中文作为基础语言 + * + * `naive ui` 语言包切换 */ diff --git a/src/layout/components/MenuTag/index.tsx b/src/layout/components/MenuTag/index.tsx index 344a5cbc..c88f8df5 100644 --- a/src/layout/components/MenuTag/index.tsx +++ b/src/layout/components/MenuTag/index.tsx @@ -1,3 +1,14 @@ +/** + * + * @author Ray + * + * @date 2022-12-08 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + import './index.scss' import { NScrollbar, NTag, NSpace } from 'naive-ui' import { useMenu } from '@/store' @@ -11,6 +22,12 @@ const MenuTag = defineComponent({ const { menuTagOptions, menuKey } = storeToRefs(menuStore) const { menuModelValueChange, spliceMenTagOptions } = menuStore + /** + * + * @param idx 索引 + * + * @remark 关闭 `tag` 菜单, 如果仅有一个则不能关闭 + */ const handleCloseTag = (idx: number) => { spliceMenTagOptions(idx) @@ -24,6 +41,10 @@ const MenuTag = defineComponent({ } } + /** + * + * @param item 当前菜单值 + */ const handleTagClick = (item: MenuOption) => { menuModelValueChange(item.key as string, item) } @@ -46,8 +67,9 @@ const MenuTag = defineComponent({ curr.key !== '/dashboard' && this.menuTagOptions.length > 1 } onClose={() => this.handleCloseTag(idx)} - type={curr.key === this.menuKey ? 'success' : 'default'} + type={curr.key === this.menuKey ? 'success' : 'info'} onClick={this.handleTagClick.bind(this, curr)} + bordered={false} > {typeof curr.label === 'function' ? curr.label() : curr.label} diff --git a/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx b/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx index 7334951c..170f57ba 100644 --- a/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx +++ b/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx @@ -38,7 +38,7 @@ const SettingDrawer = defineComponent({ const settingStore = useSetting() const { changePrimaryColor, changeSwitcher } = settingStore - const { themeValue, primaryColorOverride, menuTagLog } = + const { themeValue, primaryColorOverride, menuTagSwitch } = storeToRefs(settingStore) const modelShow = computed({ @@ -59,7 +59,7 @@ const SettingDrawer = defineComponent({ changePrimaryColor, themeValue, primaryColorOverride, - menuTagLog, + menuTagSwitch, changeSwitcher, } }, @@ -129,9 +129,9 @@ const SettingDrawer = defineComponent({ - this.changeSwitcher(bool, 'menuTagLog') + this.changeSwitcher(bool, 'menuTagSwitch') } /> diff --git a/src/layout/components/SiderBar/index.tsx b/src/layout/components/SiderBar/index.tsx index efed78be..317990fd 100644 --- a/src/layout/components/SiderBar/index.tsx +++ b/src/layout/components/SiderBar/index.tsx @@ -95,9 +95,9 @@ const SiderBar = defineComponent({ ] const iconEventMap: IconEventMapOptions = { reload: () => { - changeSwitcher(false, 'reloadRouteLog') + changeSwitcher(false, 'reloadRouteSwitch') - setTimeout(() => changeSwitcher(true, 'reloadRouteLog')) + setTimeout(() => changeSwitcher(true, 'reloadRouteSwitch')) }, setting: () => { showSettings.value = true diff --git a/src/layout/index.tsx b/src/layout/index.tsx index 8160bed6..4d0e3697 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -12,12 +12,12 @@ const Layout = defineComponent({ setup() { const menuStore = useSetting() const { height: windowHeight } = useWindowSize() - const modelReloadRoute = computed(() => menuStore.reloadRouteLog) - const modelMenuTagLog = computed(() => menuStore.menuTagLog) + const modelReloadRoute = computed(() => menuStore.reloadRouteSwitch) + const modelMenuTagSwitch = computed(() => menuStore.menuTagSwitch) const cssVarsRef = computed(() => { let cssVar = {} - if (menuStore.menuTagLog) { + if (menuStore.menuTagSwitch) { cssVar = { '--layout-content-height': 'calc(100% - 110px)', } @@ -33,7 +33,7 @@ const Layout = defineComponent({ return { windowHeight, modelReloadRoute, - modelMenuTagLog, + modelMenuTagSwitch, cssVarsRef, } }, @@ -47,7 +47,7 @@ const Layout = defineComponent({ - {this.modelMenuTagLog ? : ''} + {this.modelMenuTagSwitch ? : ''} { const app = createApp(App) + setupI18n(app) + setupStore(app) setupRouter(app) @@ -32,8 +34,6 @@ const setupTemplate = () => { permissionRouter() - setupI18n(app) - app.mount('#app') } @@ -48,6 +48,8 @@ const setupWujieTemplate = () => { window.__WUJIE_MOUNT = () => { instance = createApp(App) + setupI18n(instance) + setupStore(instance) setupRouter(instance) @@ -56,8 +58,6 @@ const setupWujieTemplate = () => { permissionRouter() - setupI18n(instance) - instance.mount('#app') } diff --git a/src/router/modules/index.ts b/src/router/modules/index.ts index a3493522..64479d2c 100644 --- a/src/router/modules/index.ts +++ b/src/router/modules/index.ts @@ -4,8 +4,9 @@ import error from './error' import echart from './echart' import scrollReveal from './scroll-reveal' import axios from './axios' +import table from './table' -const routes = [dashboard, echart, axios, scrollReveal, error, reyl] +const routes = [dashboard, echart, table, axios, scrollReveal, error, reyl] export default routes diff --git a/src/router/modules/table.ts b/src/router/modules/table.ts new file mode 100644 index 00000000..fc9cfb77 --- /dev/null +++ b/src/router/modules/table.ts @@ -0,0 +1,9 @@ +export default { + path: '/table', + name: 'table', + component: () => import('@/views/table/index'), + meta: { + i18nKey: 'Table', + icon: 'table', + }, +} diff --git a/src/store/modules/setting.ts b/src/store/modules/setting.ts index c15b3ed9..0e854e0f 100644 --- a/src/store/modules/setting.ts +++ b/src/store/modules/setting.ts @@ -1,3 +1,5 @@ +import { useNaiveLocal, useDefaultNaiveLocal } from '@/language/index' + export const useSetting = defineStore( 'setting', () => { @@ -9,20 +11,29 @@ export const useSetting = defineStore( }, }, themeValue: false, // `true` 为黑夜主题, `false` 为白色主题 - reloadRouteLog: true, // 刷新路由开关 - menuTagLog: true, // 多标签页开关 + reloadRouteSwitch: true, // 刷新路由开关 + menuTagSwitch: true, // 多标签页开关 + naiveLocal: useDefaultNaiveLocal(), // `naive ui` 语言包 }) const { locale } = useI18n() const updateLocale = (key: string) => { // TODO: 修改语言 locale.value = key + settingState.naiveLocal = useNaiveLocal(key) } const changePrimaryColor = (value: string) => { settingState.primaryColorOverride.common.primaryColor = value } + /** + * + * @param bool 开关当前值 + * @param key `settingState` 对应开关属性值 + * + * @remark 仅适用于值为 `boolean` 的切换 + */ const changeSwitcher = (bool: boolean, key: keyof typeof settingState) => { ;(settingState[key] as unknown) = bool } diff --git a/src/views/table/index.tsx b/src/views/table/index.tsx new file mode 100644 index 00000000..288a8076 --- /dev/null +++ b/src/views/table/index.tsx @@ -0,0 +1,38 @@ +/** + * + * @author Ray + * + * @date 2022-12-08 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { NLayout, NCard } from 'naive-ui' +import RayTable from '@/components/RayTable/index' + +const TableView = defineComponent({ + name: 'TableView', + setup() { + return {} + }, + render() { + return ( + + + 该组件基于 Naive UI DataTable 组件封装. 实现右键菜单, 表格标题, + 操作栏等功能 + + + + + + + + + ) + }, +}) + +export default TableView