page: 📄 多语言页面待完成
This commit is contained in:
parent
024188ee3d
commit
1d98efe92e
|
@ -7,6 +7,17 @@ export interface BaseResult<T> {
|
|||
message: string;
|
||||
}
|
||||
|
||||
export interface ResultTable {
|
||||
/** 列表数据 */
|
||||
list: Array<any>;
|
||||
/** 总条目数 */
|
||||
total?: number;
|
||||
/** 每页显示条目个数 */
|
||||
pageSize?: number;
|
||||
/** 当前页数 */
|
||||
pageNo?: number;
|
||||
}
|
||||
|
||||
export type resultType = {
|
||||
accessToken?: string;
|
||||
};
|
||||
|
|
|
@ -1,9 +1,65 @@
|
|||
import { http } from '@/api/service/mockRequest';
|
||||
import type { Result } from '@/types/store/baseStoreState';
|
||||
import type { BaseResult } from '@/api/service/types';
|
||||
|
||||
/**
|
||||
* * 获取多语言内容
|
||||
*/
|
||||
export const fetchGetI18n = () => {
|
||||
return http.request<Result<object>>('get', 'getI18n');
|
||||
return http.request<BaseResult<object>>('get', 'i18n/getI18n');
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言管理---获取多语言列表
|
||||
*/
|
||||
export const fetchGetI18nList = (data: any) => {
|
||||
return http.request<BaseResult<object>>('get', `i18n/getI18nList/${data.page}/${data.pageSize}`, { data });
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言管理---添加多语言
|
||||
*/
|
||||
export const fetchAddI18n = (data: any) => {
|
||||
return http.request<BaseResult<object>>('post', 'i18n/addI18n', { data });
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言管理---更新多语言
|
||||
*/
|
||||
export const fetchUpdateI18n = (data: any) => {
|
||||
return http.request<BaseResult<object>>('put', 'i18n/updateI18n', { data });
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言管理---删除多语言
|
||||
*/
|
||||
export const fetchDeleteI18n = (data: any) => {
|
||||
return http.request<BaseResult<object>>('put', 'i18n/deleteI18n', { data });
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言类型管理---获取多语言类型列表
|
||||
*/
|
||||
export const fetchGetI18nTypeList = () => {
|
||||
return http.request<BaseResult<object>>('get', 'i18nType/getI18nTypeList');
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言类型管理---添加多语言类型
|
||||
*/
|
||||
export const fetchAddI18nType = (data: any) => {
|
||||
return http.request<BaseResult<object>>('post', 'i18nType/addI18nType', { data });
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言类型管理---更新多语言类型
|
||||
*/
|
||||
export const fetchUpdateI18nType = (data: any) => {
|
||||
return http.request<BaseResult<object>>('put', 'i18nType/updateI18nType', { data });
|
||||
};
|
||||
|
||||
/**
|
||||
* 多语言类型管理---删除多语言类型
|
||||
*/
|
||||
export const fetchDeleteI18nType = (data: any) => {
|
||||
return http.request<BaseResult<object>>('put', 'i18nType/deleteI18nType', { data });
|
||||
};
|
||||
|
|
|
@ -1,38 +1,32 @@
|
|||
import { http } from '@/api/service/request';
|
||||
import type { BaseResult } from '@/api/service/types';
|
||||
|
||||
type ResultTable = {
|
||||
/** 列表数据 */
|
||||
list: Array<any>;
|
||||
/** 总条目数 */
|
||||
total?: number;
|
||||
/** 每页显示条目个数 */
|
||||
pageSize?: number;
|
||||
/** 当前页数 */
|
||||
pageNo?: number;
|
||||
};
|
||||
import type { BaseResult, ResultTable } from '@/api/service/types';
|
||||
|
||||
/** 系统管理-用户路由获取 */
|
||||
export const getRouterAsync = () => {
|
||||
return http.request<BaseResult<any>>('get', 'router/getRouterAsync');
|
||||
};
|
||||
|
||||
/** 系统管理-菜单管理列表 */
|
||||
/** 图标管理-获取系统图标 */
|
||||
export const getMenuIconList = (data: any) => {
|
||||
return http.request<BaseResult<ResultTable>>('get', `menuIcon/getMenuIconList/${data.page}/${data.limit}`, { data });
|
||||
};
|
||||
|
||||
/** 菜单管理-列表 */
|
||||
export const getMenuList = (data?: any) => {
|
||||
return http.request<BaseResult<ResultTable>>('get', `router/getMenus`, { data });
|
||||
};
|
||||
|
||||
/** 系统管理-添加菜单 */
|
||||
/** 菜单管理-添加菜单 */
|
||||
export const addMenu = (data?: any) => {
|
||||
return http.request<BaseResult<any>>('post', `router/addMenu`, { data });
|
||||
};
|
||||
|
||||
/** 系统管理-更新菜单 */
|
||||
/** 菜单管理-更新菜单 */
|
||||
export const updateMenu = (data?: any) => {
|
||||
return http.request<BaseResult<any>>('put', `router/updateMenu`, { data });
|
||||
};
|
||||
|
||||
/** 系统管理-删除菜单 */
|
||||
/** 菜单管理-删除菜单 */
|
||||
export const deletedMenuByIds = (data?: any) => {
|
||||
return http.request<BaseResult<any>>('delete', `router/deletedMenuByIds`, { data });
|
||||
};
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
// ? 是否显示
|
||||
show: {
|
||||
type: Boolean,
|
||||
},
|
||||
// ? 点击旁白是否关闭
|
||||
clickNodalFlag: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// ? 是否按下esc关闭
|
||||
pressEscapeFlag: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// ? 返回文字
|
||||
cancelText: {
|
||||
type: String as PropType<string>,
|
||||
default: '返回',
|
||||
},
|
||||
// ? 确认文字
|
||||
confirmText: {
|
||||
type: String as PropType<string>,
|
||||
default: '确认',
|
||||
},
|
||||
});
|
||||
const emits = defineEmits(['onCancel', 'onConfirm']);
|
||||
|
||||
const dialogVisible = ref(props.show);
|
||||
|
||||
/**
|
||||
* * 返回时
|
||||
*/
|
||||
const onCancel = () => {
|
||||
emits('onCancel', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当确认时
|
||||
*/
|
||||
const onConfirm = () => {
|
||||
emits('onConfirm', false);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
() => {
|
||||
dialogVisible.value = props.show;
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-dialog v-model="dialogVisible" :close-on-click-modal="clickNodalFlag" :closeOnPressEscape="pressEscapeFlag" :onClose="onCancel" destroy-on-close draggable v-bind="$attrs">
|
||||
<template #header>
|
||||
<slot name="header" />
|
||||
</template>
|
||||
|
||||
<slot name="default" />
|
||||
|
||||
<template #footer>
|
||||
<slot name="dialogFooter">
|
||||
<div class="dialog-footer">
|
||||
<slot name="footer">
|
||||
<el-button @click="onCancel">{{ cancelText }}</el-button>
|
||||
<el-button type="primary" @click="onConfirm"> {{ confirmText }}</el-button>
|
||||
</slot>
|
||||
<slot name="footer-add" />
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
|
@ -0,0 +1,161 @@
|
|||
<script lang="ts" setup>
|
||||
import { IconJson } from '@/components/ReIcon/data';
|
||||
import { cloneDeep, isAllEmpty } from '@pureadmin/utils';
|
||||
import { computed, CSSProperties, ref, watch } from 'vue';
|
||||
import Search from '@iconify-icons/ri/search-eye-line';
|
||||
import { inputValue } from '@/components/ReIcon/src/hooks';
|
||||
|
||||
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;
|
||||
|
||||
const iconList = ref(IconJson);
|
||||
const icon = ref();
|
||||
const currentActiveType = ref('ep:');
|
||||
// 深拷贝图标数据,前端做搜索
|
||||
const copyIconList = cloneDeep(iconList.value);
|
||||
const totalPage = ref(0);
|
||||
|
||||
// 每页显示35个图标
|
||||
const pageSize = ref(35);
|
||||
const currentPage = ref(1);
|
||||
|
||||
// 搜索条件
|
||||
const filterValue = ref('');
|
||||
|
||||
const tabsList = [
|
||||
{
|
||||
label: 'Element Plus',
|
||||
name: 'ep:',
|
||||
},
|
||||
{
|
||||
label: 'Remix Icon',
|
||||
name: 'ri:',
|
||||
},
|
||||
{
|
||||
label: 'Font Awesome 5 Solid',
|
||||
name: 'fa-solid:',
|
||||
},
|
||||
];
|
||||
|
||||
const pageList = computed(() => copyIconList[currentActiveType.value].filter(i => i.includes(filterValue.value)).slice((currentPage.value - 1) * pageSize.value, currentPage.value * pageSize.value));
|
||||
|
||||
const iconItemStyle = computed((): ParameterCSSProperties => {
|
||||
return item => {
|
||||
if (inputValue.value === currentActiveType.value + item) {
|
||||
return {
|
||||
borderColor: 'var(--el-color-primary)',
|
||||
color: 'var(--el-color-primary)',
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function setVal() {
|
||||
currentActiveType.value = inputValue.value.substring(0, inputValue.value.indexOf(':') + 1);
|
||||
icon.value = inputValue.value.substring(inputValue.value.indexOf(':') + 1);
|
||||
}
|
||||
|
||||
function onAfterLeave() {
|
||||
filterValue.value = '';
|
||||
}
|
||||
|
||||
function handleClick({ props }) {
|
||||
currentPage.value = 1;
|
||||
currentActiveType.value = props.name;
|
||||
}
|
||||
|
||||
function onChangeIcon(item) {
|
||||
icon.value = item;
|
||||
inputValue.value = currentActiveType.value + item;
|
||||
}
|
||||
|
||||
function onCurrentChange(page) {
|
||||
currentPage.value = page;
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
icon.value = '';
|
||||
inputValue.value = '';
|
||||
}
|
||||
|
||||
function onBeforeEnter() {
|
||||
if (isAllEmpty(icon.value)) return;
|
||||
setVal();
|
||||
// 寻找当前图标在第几页
|
||||
const curIconIndex = copyIconList[currentActiveType.value].findIndex(i => i === icon.value);
|
||||
currentPage.value = Math.ceil((curIconIndex + 1) / pageSize.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => pageList.value,
|
||||
() => (totalPage.value = copyIconList[currentActiveType.value].filter(i => i.includes(filterValue.value)).length),
|
||||
{ immediate: true },
|
||||
);
|
||||
watch(
|
||||
() => inputValue.value,
|
||||
val => val && setVal(),
|
||||
{ immediate: true },
|
||||
);
|
||||
watch(
|
||||
() => filterValue.value,
|
||||
() => (currentPage.value = 1),
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-popover :popper-options="{ placement: 'auto' }" :width="350" popper-class="pure-popper" trigger="click" @before-enter="onBeforeEnter" @after-leave="onAfterLeave">
|
||||
<template #reference>
|
||||
<div class="w-[40px] h-[32px] cursor-pointer flex justify-center items-center">
|
||||
<IconifyIconOffline v-if="!icon" :icon="Search" />
|
||||
<IconifyIconOnline v-else :icon="inputValue" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-input v-model="filterValue" class="px-2 pt-2" clearable placeholder="搜索图标" />
|
||||
|
||||
<el-tabs v-model="currentActiveType" @tab-click="handleClick">
|
||||
<el-tab-pane v-for="(pane, index) in tabsList" :key="index" :label="pane.label" :name="pane.name">
|
||||
<el-scrollbar height="220px">
|
||||
<ul class="flex flex-wrap px-2 ml-2">
|
||||
<li
|
||||
v-for="(item, key) in pageList"
|
||||
:key="key"
|
||||
:style="iconItemStyle(item)"
|
||||
:title="item"
|
||||
class="icon-item p-2 cursor-pointer mr-2 mt-1 flex justify-center items-center border border-[#e5e7eb]"
|
||||
@click="onChangeIcon(item)"
|
||||
>
|
||||
<IconifyIconOnline :icon="currentActiveType + item" height="20px" width="20px" />
|
||||
</li>
|
||||
</ul>
|
||||
<el-empty v-show="pageList.length === 0" :description="`${filterValue} 图标不存在`" :image-size="60" />
|
||||
</el-scrollbar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div class="w-full h-9 flex items-center overflow-auto border-t border-[#e5e7eb]">
|
||||
<el-pagination
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
:total="totalPage"
|
||||
background
|
||||
class="flex-auto ml-2"
|
||||
layout="pager"
|
||||
size="small"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
<el-button bg class="justify-end mr-2 ml-2" size="small" text type="danger" @click="onClear"> 清空</el-button>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icon-item {
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
transition: all 0.4s;
|
||||
transform: scaleX(1.05);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,229 +1,23 @@
|
|||
<script setup lang="ts">
|
||||
import { IconJson } from "@/components/ReIcon/data";
|
||||
import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
|
||||
import { ref, computed, CSSProperties, watch } from "vue";
|
||||
import Search from "@iconify-icons/ri/search-eye-line";
|
||||
|
||||
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;
|
||||
<script lang="ts" setup>
|
||||
import LocalSelect from '@/components/ReIcon/src/LocalSelect.vue';
|
||||
import { inputValue } from '@/components/ReIcon/src/hooks';
|
||||
|
||||
defineOptions({
|
||||
name: "IconSelect"
|
||||
name: 'IconSelect',
|
||||
});
|
||||
|
||||
const inputValue = defineModel({ type: String });
|
||||
|
||||
const iconList = ref(IconJson);
|
||||
const icon = ref();
|
||||
const currentActiveType = ref("ep:");
|
||||
// 深拷贝图标数据,前端做搜索
|
||||
const copyIconList = cloneDeep(iconList.value);
|
||||
const totalPage = ref(0);
|
||||
// 每页显示35个图标
|
||||
const pageSize = ref(35);
|
||||
const currentPage = ref(1);
|
||||
|
||||
// 搜索条件
|
||||
const filterValue = ref("");
|
||||
|
||||
const tabsList = [
|
||||
{
|
||||
label: "Element Plus",
|
||||
name: "ep:"
|
||||
},
|
||||
{
|
||||
label: "Remix Icon",
|
||||
name: "ri:"
|
||||
},
|
||||
{
|
||||
label: "Font Awesome 5 Solid",
|
||||
name: "fa-solid:"
|
||||
}
|
||||
];
|
||||
|
||||
const pageList = computed(() =>
|
||||
copyIconList[currentActiveType.value]
|
||||
.filter(i => i.includes(filterValue.value))
|
||||
.slice(
|
||||
(currentPage.value - 1) * pageSize.value,
|
||||
currentPage.value * pageSize.value
|
||||
)
|
||||
);
|
||||
|
||||
const iconItemStyle = computed((): ParameterCSSProperties => {
|
||||
return item => {
|
||||
if (inputValue.value === currentActiveType.value + item) {
|
||||
return {
|
||||
borderColor: "var(--el-color-primary)",
|
||||
color: "var(--el-color-primary)"
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function setVal() {
|
||||
currentActiveType.value = inputValue.value.substring(
|
||||
0,
|
||||
inputValue.value.indexOf(":") + 1
|
||||
);
|
||||
icon.value = inputValue.value.substring(inputValue.value.indexOf(":") + 1);
|
||||
}
|
||||
|
||||
function onBeforeEnter() {
|
||||
if (isAllEmpty(icon.value)) return;
|
||||
setVal();
|
||||
// 寻找当前图标在第几页
|
||||
const curIconIndex = copyIconList[currentActiveType.value].findIndex(
|
||||
i => i === icon.value
|
||||
);
|
||||
currentPage.value = Math.ceil((curIconIndex + 1) / pageSize.value);
|
||||
}
|
||||
|
||||
function onAfterLeave() {
|
||||
filterValue.value = "";
|
||||
}
|
||||
|
||||
function handleClick({ props }) {
|
||||
currentPage.value = 1;
|
||||
currentActiveType.value = props.name;
|
||||
}
|
||||
|
||||
function onChangeIcon(item) {
|
||||
icon.value = item;
|
||||
inputValue.value = currentActiveType.value + item;
|
||||
}
|
||||
|
||||
function onCurrentChange(page) {
|
||||
currentPage.value = page;
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
icon.value = "";
|
||||
inputValue.value = "";
|
||||
}
|
||||
|
||||
watch(
|
||||
() => pageList.value,
|
||||
() =>
|
||||
(totalPage.value = copyIconList[currentActiveType.value].filter(i =>
|
||||
i.includes(filterValue.value)
|
||||
).length),
|
||||
{ immediate: true }
|
||||
);
|
||||
watch(
|
||||
() => inputValue.value,
|
||||
val => val && setVal(),
|
||||
{ immediate: true }
|
||||
);
|
||||
watch(
|
||||
() => filterValue.value,
|
||||
() => (currentPage.value = 1)
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="selector">
|
||||
<el-input v-model="inputValue" disabled>
|
||||
<template #append>
|
||||
<el-popover
|
||||
:width="350"
|
||||
trigger="click"
|
||||
popper-class="pure-popper"
|
||||
:popper-options="{
|
||||
placement: 'auto'
|
||||
}"
|
||||
@before-enter="onBeforeEnter"
|
||||
@after-leave="onAfterLeave"
|
||||
>
|
||||
<template #reference>
|
||||
<div
|
||||
class="w-[40px] h-[32px] cursor-pointer flex justify-center items-center"
|
||||
>
|
||||
<IconifyIconOffline v-if="!icon" :icon="Search" />
|
||||
<IconifyIconOnline v-else :icon="inputValue" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-input
|
||||
v-model="filterValue"
|
||||
class="px-2 pt-2"
|
||||
placeholder="搜索图标"
|
||||
clearable
|
||||
/>
|
||||
|
||||
<el-tabs v-model="currentActiveType" @tab-click="handleClick">
|
||||
<el-tab-pane
|
||||
v-for="(pane, index) in tabsList"
|
||||
:key="index"
|
||||
:label="pane.label"
|
||||
:name="pane.name"
|
||||
>
|
||||
<el-scrollbar height="220px">
|
||||
<ul class="flex flex-wrap px-2 ml-2">
|
||||
<li
|
||||
v-for="(item, key) in pageList"
|
||||
:key="key"
|
||||
:title="item"
|
||||
class="icon-item p-2 cursor-pointer mr-2 mt-1 flex justify-center items-center border border-[#e5e7eb]"
|
||||
:style="iconItemStyle(item)"
|
||||
@click="onChangeIcon(item)"
|
||||
>
|
||||
<IconifyIconOnline
|
||||
:icon="currentActiveType + item"
|
||||
width="20px"
|
||||
height="20px"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
<el-empty
|
||||
v-show="pageList.length === 0"
|
||||
:description="`${filterValue} 图标不存在`"
|
||||
:image-size="60"
|
||||
/>
|
||||
</el-scrollbar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<div
|
||||
class="w-full h-9 flex items-center overflow-auto border-t border-[#e5e7eb]"
|
||||
>
|
||||
<el-pagination
|
||||
class="flex-auto ml-2"
|
||||
:total="totalPage"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
layout="pager"
|
||||
background
|
||||
size="small"
|
||||
@current-change="onCurrentChange"
|
||||
/>
|
||||
<el-button
|
||||
class="justify-end mr-2 ml-2"
|
||||
type="danger"
|
||||
size="small"
|
||||
text
|
||||
bg
|
||||
@click="onClear"
|
||||
>
|
||||
清空
|
||||
</el-button>
|
||||
</div>
|
||||
</el-popover>
|
||||
<LocalSelect />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.icon-item {
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
transition: all 0.4s;
|
||||
transform: scaleX(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-tabs__nav-next) {
|
||||
font-size: 15px;
|
||||
line-height: 32px;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import type { iconType } from "./types";
|
||||
import { h, defineComponent, type Component } from "vue";
|
||||
import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
|
||||
import type { iconType } from './types';
|
||||
import { type Component, defineComponent, h, ref } from 'vue';
|
||||
import { FontIcon, IconifyIconOffline, IconifyIconOnline } from '../index';
|
||||
|
||||
export const inputValue = ref();
|
||||
|
||||
/**
|
||||
* 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
|
||||
|
@ -16,46 +18,42 @@ export function useRenderIcon(icon: any, attrs?: iconType): Component {
|
|||
if (ifReg.test(icon)) {
|
||||
// iconfont
|
||||
const name = icon.split(ifReg)[1];
|
||||
const iconName = name.slice(
|
||||
0,
|
||||
name.indexOf(" ") == -1 ? name.length : name.indexOf(" ")
|
||||
);
|
||||
const iconType = name.slice(name.indexOf(" ") + 1, name.length);
|
||||
const iconName = name.slice(0, name.indexOf(' ') == -1 ? name.length : name.indexOf(' '));
|
||||
const iconType = name.slice(name.indexOf(' ') + 1, name.length);
|
||||
return defineComponent({
|
||||
name: "FontIcon",
|
||||
name: 'FontIcon',
|
||||
render() {
|
||||
return h(FontIcon, {
|
||||
icon: iconName,
|
||||
iconType,
|
||||
...attrs
|
||||
...attrs,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
} else if (typeof icon === "function" || typeof icon?.render === "function") {
|
||||
} else if (typeof icon === 'function' || typeof icon?.render === 'function') {
|
||||
// svg
|
||||
return attrs ? h(icon, { ...attrs }) : icon;
|
||||
} else if (typeof icon === "object") {
|
||||
} else if (typeof icon === 'object') {
|
||||
return defineComponent({
|
||||
name: "OfflineIcon",
|
||||
name: 'OfflineIcon',
|
||||
render() {
|
||||
return h(IconifyIconOffline, {
|
||||
icon: icon,
|
||||
...attrs
|
||||
...attrs,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之
|
||||
return defineComponent({
|
||||
name: "Icon",
|
||||
name: 'Icon',
|
||||
render() {
|
||||
const IconifyIcon =
|
||||
icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline;
|
||||
const IconifyIcon = icon && icon.includes(':') ? IconifyIconOnline : IconifyIconOffline;
|
||||
return h(IconifyIcon, {
|
||||
icon: icon,
|
||||
...attrs
|
||||
...attrs,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts" setup>
|
||||
defineProps({
|
||||
status: {
|
||||
type: Boolean,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-tag v-show="status" effect="dark" size="large" type="success">是</el-tag>
|
||||
<el-tag v-show="!status" effect="dark" size="large" type="danger">否</el-tag>
|
||||
</template>
|
|
@ -1,34 +1,21 @@
|
|||
<script lang="ts" setup>
|
||||
import {
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
onMounted,
|
||||
PropType,
|
||||
ref,
|
||||
unref,
|
||||
watch
|
||||
} from "vue";
|
||||
import { rendTipProps } from "@/components/TableBar/utils/tableConfig";
|
||||
import {
|
||||
cellHeaderStyle,
|
||||
getDropdownItemStyle,
|
||||
iconClass,
|
||||
topClass
|
||||
} from "@/components/TableBar/utils/tableStyle";
|
||||
import PureTable from "@pureadmin/table";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import RefreshIcon from "@/assets/table-bar/refresh.svg?component";
|
||||
import CollapseIcon from "@/assets/table-bar/collapse.svg?component";
|
||||
import SettingIcon from "@/assets/table-bar/settings.svg?component";
|
||||
import { cloneDeep, getKeyList, isBoolean, isFunction } from "@pureadmin/utils";
|
||||
import DragIcon from "@/assets/table-bar/drag.svg?component";
|
||||
import Sortable from "sortablejs";
|
||||
import { $t } from "@/plugins/i18n";
|
||||
import { DeleteFilled, EditPen } from "@element-plus/icons-vue";
|
||||
import { useRenderIcon } from "@/components/CommonIcon/src/hooks";
|
||||
import Refresh from "@iconify-icons/ep/refresh";
|
||||
import { FormInstance } from "element-plus";
|
||||
import { getCurrentInstance, nextTick, onMounted, PropType, ref, unref, watch } from 'vue';
|
||||
import { rendTipProps } from '@/components/TableBar/utils/tableConfig';
|
||||
import { cellHeaderStyle, getDropdownItemStyle, iconClass, topClass } from '@/components/TableBar/utils/tableStyle';
|
||||
import PureTable from '@pureadmin/table';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import RefreshIcon from '@/assets/table-bar/refresh.svg?component';
|
||||
import CollapseIcon from '@/assets/table-bar/collapse.svg?component';
|
||||
import SettingIcon from '@/assets/table-bar/settings.svg?component';
|
||||
import { cloneDeep, getKeyList, isBoolean, isFunction } from '@pureadmin/utils';
|
||||
import DragIcon from '@/assets/table-bar/drag.svg?component';
|
||||
import Sortable from 'sortablejs';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { DeleteFilled, EditPen } from '@element-plus/icons-vue';
|
||||
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
|
||||
import Refresh from '@iconify-icons/ep/refresh';
|
||||
import { FormInstance } from 'element-plus';
|
||||
|
||||
// * 传入数据
|
||||
const props = defineProps({
|
||||
|
@ -41,55 +28,55 @@ const props = defineProps({
|
|||
// 表格头部查询
|
||||
tableQueryFormVisible: { type: Boolean, default: true },
|
||||
// 页面字体大小,small | default | large
|
||||
size: { type: String as PropType<any>, default: "default" },
|
||||
size: { type: String as PropType<any>, default: 'default' },
|
||||
// 分页器参数
|
||||
pagination: { type: Object, default: Object },
|
||||
// 选择行发生变化
|
||||
handleSelectionChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
},
|
||||
// 分页大小变化
|
||||
handleSizeChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
},
|
||||
// 当前页变化
|
||||
handleCurrentChange: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
},
|
||||
// 表单参数
|
||||
form: {
|
||||
type: Object as PropType<any>,
|
||||
default: Object
|
||||
default: Object,
|
||||
},
|
||||
// 表格的key值
|
||||
tableKey: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: "0"
|
||||
default: '0',
|
||||
},
|
||||
// 表格标题
|
||||
tableTitle: { type: String, default: "" },
|
||||
tableTitle: { type: String, default: '' },
|
||||
// 表格修改
|
||||
tableEdit: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
}, // 表格删除
|
||||
tableDelete: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
},
|
||||
// 刷新时
|
||||
onReFresh: {
|
||||
type: Function as PropType<Function>,
|
||||
default: () => {}
|
||||
default: () => {},
|
||||
},
|
||||
onSearch: { type: Function as PropType<any> },
|
||||
model: { type: Object as PropType<any> }
|
||||
model: { type: Object as PropType<any> },
|
||||
});
|
||||
|
||||
const emit = defineEmits(["changeColumn"]);
|
||||
const emit = defineEmits(['changeColumn']);
|
||||
const { t, locale } = useI18n();
|
||||
const route = useRoute();
|
||||
// 是否全选
|
||||
|
@ -100,16 +87,10 @@ const isIndeterminate = ref(false);
|
|||
// 动态行
|
||||
const dynamicColumns = ref(props.column);
|
||||
// 过滤是否选中的列
|
||||
const filterColumns = cloneDeep(props.column).filter(column =>
|
||||
isBoolean(column?.hide)
|
||||
? !column.hide
|
||||
: !(isFunction(column?.hide) && column?.hide())
|
||||
);
|
||||
const filterColumns = cloneDeep(props.column).filter(column => (isBoolean(column?.hide) ? !column.hide : !(isFunction(column?.hide) && column?.hide())));
|
||||
// 选择当前列
|
||||
const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label"));
|
||||
const checkColumnList = ref(
|
||||
getKeyList(cloneDeep(dynamicColumns.value), "label")
|
||||
);
|
||||
const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), 'label'));
|
||||
const checkColumnList = ref(getKeyList(cloneDeep(dynamicColumns.value), 'label'));
|
||||
const instance = getCurrentInstance()!;
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
|
||||
|
@ -128,9 +109,7 @@ const handleTableSizeClick = (value: string) => {
|
|||
const handleCheckAllChange = (val: boolean) => {
|
||||
checkedColumns.value = val ? checkColumnList.value : [];
|
||||
isIndeterminate.value = false;
|
||||
dynamicColumns.value.map(column =>
|
||||
val ? (column.hide = false) : (column.hide = true)
|
||||
);
|
||||
dynamicColumns.value.map(column => (val ? (column.hide = false) : (column.hide = true)));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -141,8 +120,7 @@ const handleCheckedColumnsChange = (value: string[]) => {
|
|||
checkedColumns.value = value;
|
||||
const checkedCount = value.length;
|
||||
checkAll.value = checkedCount === checkColumnList.value.length;
|
||||
isIndeterminate.value =
|
||||
checkedCount > 0 && checkedCount < checkColumnList.value.length;
|
||||
isIndeterminate.value = checkedCount > 0 && checkedCount < checkColumnList.value.length;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -150,9 +128,7 @@ const handleCheckedColumnsChange = (value: string[]) => {
|
|||
* @param label
|
||||
*/
|
||||
const handleCheckColumnListChange = (label: string) => {
|
||||
dynamicColumns.value.filter(item => item.label === label)[0].hide = !(
|
||||
event.target as any
|
||||
).checked;
|
||||
dynamicColumns.value.filter(item => item.label === label)[0].hide = !(event.target as any).checked;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -173,12 +149,12 @@ const onReset = async () => {
|
|||
checkAll.value = true;
|
||||
isIndeterminate.value = false;
|
||||
// 当前选中的列
|
||||
checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label");
|
||||
checkedColumns.value = getKeyList(cloneDeep(filterColumns), 'label');
|
||||
// ? 重新赋值,拖拽排序不会改变原有值,响应式数据的特性 直接对 ref 或 reactive 创建的变量进行赋值可能不会触发视图的更新
|
||||
// ? Proxy 来追踪属性的访问和修改,使用异步方式确保正确更新视图
|
||||
checkColumnList.value = [];
|
||||
await nextTick(() => {
|
||||
checkColumnList.value = getKeyList(filterColumns, "label");
|
||||
checkColumnList.value = getKeyList(filterColumns, 'label');
|
||||
});
|
||||
|
||||
// checkedColumns 是原有顺序,根据这个顺序重新得到list
|
||||
|
@ -190,18 +166,16 @@ const onReset = async () => {
|
|||
});
|
||||
});
|
||||
|
||||
emit("changeColumn", list);
|
||||
emit('changeColumn', list);
|
||||
};
|
||||
|
||||
/** 列展示拖拽排序 */
|
||||
const rowDrop = (event: any) => {
|
||||
nextTick(() => {
|
||||
const wrapper: HTMLElement = (
|
||||
instance?.proxy?.$refs[`GroupRef${unref(props.tableKey)}`] as any
|
||||
).$el.firstElementChild;
|
||||
const wrapper: HTMLElement = (instance?.proxy?.$refs[`GroupRef${unref(props.tableKey)}`] as any).$el.firstElementChild;
|
||||
Sortable.create(wrapper, {
|
||||
animation: 300,
|
||||
handle: ".drag-btn",
|
||||
handle: '.drag-btn',
|
||||
onEnd: ({ newIndex, oldIndex, item }) => {
|
||||
const targetThElem = item;
|
||||
const wrapperElem = targetThElem.parentNode as HTMLElement;
|
||||
|
@ -213,17 +187,14 @@ const rowDrop = (event: any) => {
|
|||
if (newIndex > oldIndex) {
|
||||
wrapperElem.insertBefore(targetThElem, oldThElem);
|
||||
} else {
|
||||
wrapperElem.insertBefore(
|
||||
targetThElem,
|
||||
oldThElem ? oldThElem.nextElementSibling : oldThElem
|
||||
);
|
||||
wrapperElem.insertBefore(targetThElem, oldThElem ? oldThElem.nextElementSibling : oldThElem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
|
||||
dynamicColumns.value.splice(newIndex, 0, currentRow);
|
||||
emit("changeColumn", dynamicColumns.value);
|
||||
}
|
||||
emit('changeColumn', dynamicColumns.value);
|
||||
},
|
||||
});
|
||||
}).then();
|
||||
};
|
||||
|
@ -248,30 +219,15 @@ onMounted(() => {
|
|||
<template>
|
||||
<div class="main">
|
||||
<!-- 表单设置,外加插槽 -->
|
||||
<el-form
|
||||
v-show="tableQueryFormVisible"
|
||||
ref="ruleFormRef"
|
||||
:inline="true"
|
||||
:model="model"
|
||||
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
|
||||
@submit="onSearch"
|
||||
>
|
||||
<el-form v-show="tableQueryFormVisible" ref="ruleFormRef" :inline="true" :model="model" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto" @submit="onSearch">
|
||||
<slot name="tableForm" />
|
||||
<el-form-item>
|
||||
<el-button
|
||||
:icon="useRenderIcon('ri:search-line')"
|
||||
:loading="loading"
|
||||
type="primary"
|
||||
@click="onSearch"
|
||||
>
|
||||
{{ $t("buttons.search") }}
|
||||
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch">
|
||||
{{ $t('buttons.search') }}
|
||||
</el-button>
|
||||
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(ruleFormRef)">
|
||||
{{ $t('buttons.rest') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
:icon="useRenderIcon(Refresh)"
|
||||
@click="resetForm(ruleFormRef)"
|
||||
>
|
||||
{{ $t("buttons.rest") }}</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
@ -294,11 +250,7 @@ onMounted(() => {
|
|||
</div>
|
||||
|
||||
<!-- 表格刷新按钮 -->
|
||||
<RefreshIcon
|
||||
v-tippy="rendTipProps('刷新')"
|
||||
:class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`"
|
||||
@click="onReFresh"
|
||||
/>
|
||||
<RefreshIcon v-tippy="rendTipProps('刷新')" :class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`" @click="onReFresh" />
|
||||
<el-divider direction="vertical" />
|
||||
|
||||
<!-- 选择表格大小 -->
|
||||
|
@ -306,23 +258,14 @@ onMounted(() => {
|
|||
<CollapseIcon :class="`w-[16px] ${iconClass()}`" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="translation">
|
||||
<el-dropdown-item
|
||||
:style="getDropdownItemStyle(size, 'large')"
|
||||
@click="handleTableSizeClick('large')"
|
||||
>
|
||||
{{ $t("style.larger") }}
|
||||
<el-dropdown-item :style="getDropdownItemStyle(size, 'large')" @click="handleTableSizeClick('large')">
|
||||
{{ $t('style.larger') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:style="getDropdownItemStyle(size, 'default')"
|
||||
@click="handleTableSizeClick('default')"
|
||||
>
|
||||
{{ t("style.default") }}
|
||||
<el-dropdown-item :style="getDropdownItemStyle(size, 'default')" @click="handleTableSizeClick('default')">
|
||||
{{ t('style.default') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
:style="getDropdownItemStyle(size, 'small')"
|
||||
@click="handleTableSizeClick('small')"
|
||||
>
|
||||
{{ t("style.small") }}
|
||||
<el-dropdown-item :style="getDropdownItemStyle(size, 'small')" @click="handleTableSizeClick('small')">
|
||||
{{ t('style.small') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
|
@ -330,63 +273,26 @@ onMounted(() => {
|
|||
<el-divider direction="vertical" />
|
||||
|
||||
<!-- 表格列设置 -->
|
||||
<el-popover
|
||||
:popper-style="{ padding: 0 }"
|
||||
placement="bottom-start"
|
||||
trigger="click"
|
||||
width="200"
|
||||
>
|
||||
<el-popover :popper-style="{ padding: 0 }" placement="bottom-start" trigger="click" width="200">
|
||||
<template #reference>
|
||||
<SettingIcon
|
||||
v-tippy="rendTipProps('列设置')"
|
||||
:class="`w-[16px] ${iconClass()}`"
|
||||
/>
|
||||
<SettingIcon v-tippy="rendTipProps('列设置')" :class="`w-[16px] ${iconClass()}`" />
|
||||
</template>
|
||||
|
||||
<div :class="topClass()">
|
||||
<el-checkbox
|
||||
v-model="checkAll"
|
||||
:indeterminate="isIndeterminate"
|
||||
class="!-mr-1"
|
||||
label="列展示"
|
||||
@change="handleCheckAllChange"
|
||||
/>
|
||||
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" class="!-mr-1" label="列展示" @change="handleCheckAllChange" />
|
||||
<el-button link type="primary" @click="onReset">
|
||||
{{ t("buttons.rest") }}</el-button
|
||||
>
|
||||
{{ t('buttons.rest') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="pt-[6px] pl-[11px]">
|
||||
<el-scrollbar max-height="36vh">
|
||||
<el-checkbox-group
|
||||
:ref="`GroupRef${unref(props.tableKey)}`"
|
||||
:modelValue="checkedColumns"
|
||||
@change="handleCheckedColumnsChange"
|
||||
>
|
||||
<el-space
|
||||
:alignment="'flex-start'"
|
||||
:size="0"
|
||||
direction="vertical"
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in checkColumnList"
|
||||
:key="index"
|
||||
class="flex items-center"
|
||||
>
|
||||
<DragIcon
|
||||
:class="`drag-btn w-[16px] mr-2 ${isFixedColumn(item) ? '!cursor-no-drop' : '!cursor-grab'}`"
|
||||
@mouseenter.prevent="rowDrop"
|
||||
/>
|
||||
<el-checkbox
|
||||
:key="index"
|
||||
:label="item"
|
||||
:value="item"
|
||||
@change="handleCheckColumnListChange(item)"
|
||||
>
|
||||
<span
|
||||
:title="item"
|
||||
class="inline-block w-[120px] truncate hover:text-text_color_primary"
|
||||
>
|
||||
<el-checkbox-group :ref="`GroupRef${unref(props.tableKey)}`" :modelValue="checkedColumns" @change="handleCheckedColumnsChange">
|
||||
<el-space :alignment="'flex-start'" :size="0" direction="vertical">
|
||||
<div v-for="(item, index) in checkColumnList" :key="index" class="flex items-center">
|
||||
<DragIcon :class="`drag-btn w-[16px] mr-2 ${isFixedColumn(item) ? '!cursor-no-drop' : '!cursor-grab'}`" @mouseenter.prevent="rowDrop" />
|
||||
<el-checkbox :key="index" :label="item" :value="item" @change="handleCheckColumnListChange(item)">
|
||||
<span :title="item" class="inline-block w-[120px] truncate hover:text-text_color_primary">
|
||||
{{ item }}
|
||||
</span>
|
||||
</el-checkbox>
|
||||
|
@ -421,29 +327,13 @@ onMounted(() => {
|
|||
@page-current-change="handleCurrentChange"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<template
|
||||
v-for="item in column"
|
||||
:key="item.prop"
|
||||
v-slot:[item.slot]="scope"
|
||||
v-bind="item"
|
||||
>
|
||||
<template v-for="item in column" :key="item.prop" v-slot:[item.slot]="scope" v-bind="item">
|
||||
<slot :name="item.slot" v-bind="scope" />
|
||||
<slot v-if="item.slot === 'operation'" name="operation">
|
||||
<el-button
|
||||
:icon="EditPen"
|
||||
link
|
||||
type="warning"
|
||||
@click="tableEdit(scope)"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-popconfirm
|
||||
:title="t('table.popConfirmTitle')"
|
||||
@confirm="tableDelete(scope)"
|
||||
>
|
||||
<el-button :icon="EditPen" link type="warning" @click="tableEdit(scope)">修改 </el-button>
|
||||
<el-popconfirm :title="t('table.popConfirmTitle')" @confirm="tableDelete(scope)">
|
||||
<template #reference>
|
||||
<el-button :icon="DeleteFilled" link type="danger"
|
||||
>删除</el-button
|
||||
>
|
||||
<el-button :icon="DeleteFilled" link type="danger">删除 </el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</slot>
|
||||
|
|
|
@ -169,19 +169,16 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
const isFixedColumn = (label: string) => {
|
||||
return dynamicColumns.value.filter(item => $t(item.label) === $t(label))[0].fixed ? true : false;
|
||||
return !!dynamicColumns.value.filter(item => $t(item.label) === $t(label))[0].fixed;
|
||||
};
|
||||
|
||||
const rendTippyProps = (content: string) => {
|
||||
// https://vue-tippy.netlify.app/props
|
||||
return {
|
||||
const rendTippyProps = (content: string) => ({
|
||||
content,
|
||||
offset: [0, 18],
|
||||
duration: [300, 0],
|
||||
followCursor: true,
|
||||
hideOnClick: 'toggle',
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
const reference = {
|
||||
reference: () => <SettingIcon class={['w-[16px]', iconClass.value]} v-tippy={rendTippyProps('列设置')} />,
|
||||
|
@ -198,9 +195,7 @@ export default defineComponent({
|
|||
<>
|
||||
<ExpandIcon
|
||||
class={['w-[16px]', iconClass.value]}
|
||||
style={{
|
||||
transform: isExpandAll.value ? 'none' : 'rotate(-90deg)',
|
||||
}}
|
||||
style={{ transform: isExpandAll.value ? 'none' : 'rotate(-90deg)' }}
|
||||
v-tippy={rendTippyProps(isExpandAll.value ? '折叠' : '展开')}
|
||||
onClick={() => onExpand()}
|
||||
/>
|
||||
|
@ -245,12 +240,7 @@ export default defineComponent({
|
|||
</el-popover>
|
||||
<el-divider direction='vertical' />
|
||||
|
||||
<iconifyIconOffline
|
||||
class={['w-[16px]', iconClass.value]}
|
||||
icon={isFullscreen.value ? ExitFullscreen : Fullscreen}
|
||||
v-tippy={isFullscreen.value ? '退出全屏' : '全屏'}
|
||||
onClick={() => onFullscreen()}
|
||||
/>
|
||||
<iconifyIconOffline class={['w-[16px]', iconClass.value]} icon={isFullscreen.value ? ExitFullscreen : Fullscreen} v-tippy={isFullscreen.value ? '退出全屏' : '全屏'} onClick={onFullscreen} />
|
||||
</div>
|
||||
</div>
|
||||
{slots.default({
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* * 是否默认
|
||||
*/
|
||||
export const isDefaultOptions = [
|
||||
{ value: true, label: '是' },
|
||||
{ value: false, label: '否' },
|
||||
];
|
||||
|
||||
/**
|
||||
* * 是否显示
|
||||
*/
|
||||
export const isDefaultVisibleOptions = [
|
||||
{ value: true, label: '显示' },
|
||||
{ value: false, label: '不显示' },
|
||||
];
|
||||
|
||||
/**
|
||||
* * 性别
|
||||
*/
|
||||
export const sexConstant = [
|
||||
{ value: 1, label: '男' },
|
||||
{ value: 0, label: '女' },
|
||||
];
|
||||
|
||||
/**
|
||||
* * 分页默认数组个数
|
||||
*/
|
||||
export const pageSizes: number[] = [15, 30, 50, 100, 150, 200, 300];
|
|
@ -1,6 +1,7 @@
|
|||
// import { fetchGetI18n } from '@/api/mock/i18n';
|
||||
import { defineStore } from 'pinia';
|
||||
import { fetchGetI18n } from '@/api/v1/i18n';
|
||||
import { fetchAddI18n, fetchDeleteI18n, fetchGetI18n, fetchGetI18nList, fetchUpdateI18n } from '@/api/v1/i18n';
|
||||
import { pageSizes } from '@/enums/baseConstant';
|
||||
import { storeMessage } from '@/utils/message';
|
||||
|
||||
export const userI18nStore = defineStore('i18nStore', {
|
||||
persist: true,
|
||||
|
@ -8,6 +9,24 @@ export const userI18nStore = defineStore('i18nStore', {
|
|||
return {
|
||||
// ? 多语言内容
|
||||
i18n: {},
|
||||
// 多语言列表
|
||||
i18nDataList: [],
|
||||
// 多语言类型
|
||||
i18nTypeList: [],
|
||||
isAddShown: false,
|
||||
// ? 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
loading: false,
|
||||
// 添加弹窗
|
||||
addDialogVisible: false,
|
||||
// 更新弹窗
|
||||
updateDialogVisible: false,
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
|
@ -29,5 +48,36 @@ export const userI18nStore = defineStore('i18nStore', {
|
|||
this.i18n = data;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* * 获取多语言列表
|
||||
*/
|
||||
async getI18nMangeList(data: any) {
|
||||
const result = await fetchGetI18nList(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 添加多语言
|
||||
*/
|
||||
async addI18n(data: any) {
|
||||
const result = await fetchAddI18n(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 更新多语言
|
||||
*/
|
||||
async updateI18n(data: any) {
|
||||
const result = await fetchUpdateI18n(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 删除多语言
|
||||
*/
|
||||
async deleteI18n(data: any) {
|
||||
const result = await fetchDeleteI18n(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { fetchAddI18nType, fetchDeleteI18nType, fetchGetI18nTypeList, fetchUpdateI18nType } from '@/api/v1/i18n';
|
||||
import { pageSizes } from '@/enums/baseConstant';
|
||||
import { storeMessage } from '@/utils/message';
|
||||
|
||||
export const userI18nTypeStore = defineStore('i18nTypeStore', {
|
||||
persist: true,
|
||||
state() {
|
||||
return {
|
||||
// 多语言列表
|
||||
datalist: [],
|
||||
isAddShown: false,
|
||||
// ? 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
loading: false,
|
||||
// 添加弹窗
|
||||
addDialogVisible: false,
|
||||
// 更新弹窗
|
||||
updateDialogVisible: false,
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
actions: {
|
||||
/**
|
||||
* * 获取多语言类型
|
||||
*/
|
||||
async getI18nTypeList() {
|
||||
const result = await fetchGetI18nTypeList();
|
||||
return storeMessage(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 添加多语言类型
|
||||
*/
|
||||
async addI18nType(data: any) {
|
||||
const result = await fetchAddI18nType(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 修改多语言类型
|
||||
*/
|
||||
async updateI18nType(data: any) {
|
||||
const result = await fetchUpdateI18nType(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* * 删除多语言类型
|
||||
*/
|
||||
async deleteI18nType(data: any) {
|
||||
const result = await fetchDeleteI18nType(data);
|
||||
return storeMessage(result);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { getMenuIconList } from '@/api/v1/system';
|
||||
|
||||
export const userMenuIconStore = defineStore('menuIconStore', {
|
||||
state() {
|
||||
return {
|
||||
menuIconList: [],
|
||||
menuIconPage: { page: 1, limit: 30, total: 0 },
|
||||
};
|
||||
},
|
||||
getters: {},
|
||||
actions: {
|
||||
/**
|
||||
* * 获取系统图标列表
|
||||
*/
|
||||
async getMenuIconList() {
|
||||
const result = await getMenuIconList(this.menuIconPage);
|
||||
if (result.code === 200) {
|
||||
this.menuIconList = result.data.list;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import type { VNode } from 'vue';
|
||||
import { isFunction } from '@pureadmin/utils';
|
||||
import { ElMessage, type MessageHandler } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox, type MessageHandler } from 'element-plus';
|
||||
import type { BaseResult } from '@/api/service/types';
|
||||
|
||||
type messageStyle = 'el' | 'antd';
|
||||
|
@ -31,6 +31,15 @@ interface MessageParams {
|
|||
onClose?: Function | null;
|
||||
}
|
||||
|
||||
// 消息盒
|
||||
interface MessageBox {
|
||||
message: string | undefined;
|
||||
title: string | undefined;
|
||||
confirmMessage: any;
|
||||
cancelMessage: any;
|
||||
showMessage: boolean;
|
||||
}
|
||||
|
||||
/** 用法非常简单,参考 src/views/components/message/index.vue 文件 */
|
||||
|
||||
/**
|
||||
|
@ -91,3 +100,34 @@ export const storeMessage = (result: BaseResult<any>) => {
|
|||
message(result.message, { type: 'success' });
|
||||
return true;
|
||||
};
|
||||
|
||||
const defaultBoxOption: MessageBox = {
|
||||
showMessage: false,
|
||||
message: '',
|
||||
title: '',
|
||||
confirmMessage: undefined,
|
||||
cancelMessage: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* 消息弹窗确认
|
||||
* @param type
|
||||
* @param option
|
||||
*/
|
||||
export const messageBox = async (option: MessageBox = defaultBoxOption, type: any = 'warning') => {
|
||||
return ElMessageBox.confirm(option.message, option.title, {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '返回',
|
||||
type,
|
||||
draggable: true,
|
||||
overflow: true,
|
||||
})
|
||||
.then(() => {
|
||||
option.showMessage && ElMessage({ type: 'success', message: option.confirmMessage });
|
||||
return true;
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({ type: 'warning', message: option.cancelMessage });
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import LanguageAdd from '@/views/i18n/i18n-setting/language-add.vue';
|
||||
import LanguageUpdate from '@/views/i18n/i18n-setting/language-update.vue';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { addDialogVisible, getI18nDataList, onDelete, updateDialogVisible } from '@/views/i18n/i18n-setting/utils/hook';
|
||||
import { useRenderIcon } from '@/components/ReIcon/src/hooks';
|
||||
import AddFill from '@iconify-icons/ri/add-circle-line';
|
||||
import EditPen from '@iconify-icons/ep/edit-pen';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import Delete from '@iconify-icons/ep/delete';
|
||||
import PureTableBar from '@/components/TableBar/src/bar';
|
||||
import PureTable from '@pureadmin/table';
|
||||
import { columns } from '@/views/i18n/i18n-setting/utils/columns';
|
||||
|
||||
const tableRef = ref();
|
||||
const i18nStore = userI18nStore();
|
||||
|
||||
onMounted(() => {
|
||||
getI18nDataList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<language-add v-if="addDialogVisible" />
|
||||
<language-update v-if="updateDialogVisible" />
|
||||
|
||||
<PureTableBar :columns="columns" :tableRef="tableRef?.getTableRef()" title="多语言管理" @fullscreen="tableRef.setAdaptive()" @refresh="getI18nDataList">
|
||||
<template #buttons>
|
||||
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="addDialogVisible = true"> 添加多语言</el-button>
|
||||
</template>
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
:adaptiveConfig="{ offsetBottom: 45 }"
|
||||
:columns="dynamicColumns"
|
||||
:data="i18nStore.i18nDataList"
|
||||
:header-cell-style="{ background: 'var(--el-fill-color-light)', color: 'var(--el-text-color-primary)' }"
|
||||
:loading="i18nStore.loading"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
row-key="id"
|
||||
showOverflowTooltip
|
||||
table-layout="auto"
|
||||
>
|
||||
<template #operation="{ row }">
|
||||
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary"> 修改 </el-button>
|
||||
<el-button v-show="row.menuType !== 3" :icon="useRenderIcon(AddFill)" :size="size" class="reset-margin" link type="primary"> 新增 </el-button>
|
||||
<el-popconfirm :title="`是否确认删除菜单名称为${$t(row.title)}的这条数据${row?.children?.length > 0 ? '注意下级菜单也会一并删除,请谨慎操作' : ''}`" @confirm="onDelete(row)">
|
||||
<template #reference>
|
||||
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,67 @@
|
|||
<script lang="ts" setup>
|
||||
import LanguageDialog from '@/views/i18n/i18n-setting/language-dialog.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { addDialogVisible } from '@/views/i18n/i18n-setting/utils/hook';
|
||||
|
||||
const i18nStore = userI18nStore();
|
||||
const dialogRef = ref();
|
||||
const form = reactive({
|
||||
languageId: '',
|
||||
keyName: '',
|
||||
translate: '',
|
||||
parentId: '',
|
||||
});
|
||||
|
||||
/**
|
||||
* * 关闭弹窗
|
||||
*/
|
||||
const onClose = () => {
|
||||
addDialogVisible.value = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 添加内容
|
||||
*/
|
||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await i18nStore.addI18n(form);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
addDialogVisible.value = false;
|
||||
await i18nStore.getI18nMangeList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* * 继续添加内容
|
||||
*/
|
||||
const onAddContinue = (value: any) => {
|
||||
const formEl: FormInstance | undefined = value.ruleFormRef;
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await i18nStore.addI18n(form);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
await i18nStore.getI18nMangeList();
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<language-dialog ref="dialogRef" :form="form" :on-close="onClose" :on-submit="onSubmit" :visible="addDialogVisible" title="添加多语言内容">
|
||||
<template #footer>
|
||||
<el-button type="success" @click="onAddContinue(dialogRef)">继续添加</el-button>
|
||||
</template>
|
||||
</language-dialog>
|
||||
</template>
|
|
@ -1,10 +1,9 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
import SimpleDialog from '@/components/Dialog/SimpleDialog.vue';
|
||||
import SimpleDialog from '@/components/BaseDialog/SimpleDialog.vue';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { rules } from '@/views/i18n/language-setting/utils/columns';
|
||||
import { rules } from '@/views/i18n/i18n-setting/utils/columns';
|
||||
|
||||
defineProps({
|
||||
// 是否显示弹窗
|
||||
|
@ -33,7 +32,6 @@ defineProps({
|
|||
});
|
||||
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
const i18nTypeStore = useI18nTypeStore();
|
||||
const i18nStore = userI18nStore();
|
||||
|
||||
defineExpose({
|
||||
|
@ -44,15 +42,9 @@ defineExpose({
|
|||
<template>
|
||||
<SimpleDialog :show="visible" :title="title" width="600" @onCancel="onClose" @onConfirm="onSubmit(ruleFormRef)">
|
||||
<el-form ref="ruleFormRef" :model="form" :rules="rules" isDefault-icon label-position="left" label-width="135px">
|
||||
<el-form-item label="选择添加语言分类" prop="parentId">
|
||||
<el-select v-model="form.parentId!" clearable filterable placeholder="选择添加语言分类">
|
||||
<el-option v-for="item in i18nStore.languageParentList" :key="item.id" :label="item.translate" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="选择添加语言分类" prop="languageId">
|
||||
<el-select v-model="form.languageId!" filterable placeholder="选择添加语言分类">
|
||||
<el-option v-for="item in i18nTypeStore.languageTypeMap" :key="item.id" :label="item.value" :value="item.id" />
|
||||
<el-option v-for="item in i18nStore.i18nTypeList" :key="item.id" :label="item.value" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<script lang="ts" setup>
|
||||
import LanguageDialog from '@/views/i18n/i18n-setting/language-dialog.vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { updateDialogVisible, updateForm } from '@/views/i18n/i18n-setting/utils/hook';
|
||||
|
||||
const i18nStore = userI18nStore();
|
||||
|
||||
/**
|
||||
* * 关闭弹窗
|
||||
*/
|
||||
const onClose = () => {
|
||||
updateDialogVisible.value = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 添加内容
|
||||
*/
|
||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await i18nStore.updateI18n(updateForm);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
updateDialogVisible.value = false;
|
||||
await i18nStore.getI18nMangeList();
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<language-dialog :form="updateForm" :on-close="onClose" :on-submit="onSubmit" :visible="updateDialogVisible" title="修改多语言内容" />
|
||||
</template>
|
|
@ -1,17 +1,16 @@
|
|||
// 多语言表格列字段
|
||||
import { reactive } from 'vue';
|
||||
import type { FormRules } from 'element-plus';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
|
||||
export const columns: TableColumnList = [
|
||||
{ type: 'selection' },
|
||||
{ type: 'index', label: $t('table.tableNumber'), width: 100 },
|
||||
{ label: $t('i18n.keyName'), prop: 'keyName' },
|
||||
{ label: $t('i18n.translate'), prop: 'translate' },
|
||||
{ label: $t('i18n.languageSummary'), prop: 'languageSummary' },
|
||||
{ label: $t('i18n.languageName'), prop: 'languageName' },
|
||||
{ label: $t('i18n.parentKeyName'), prop: 'parentKeyName' },
|
||||
{ label: $t('table.operation'), prop: 'operation', slot: 'operation' },
|
||||
// { type: 'selection' },
|
||||
// { type: 'index', label: 'table.tableNumber', width: 100 },
|
||||
{ label: 'i18n.keyName', prop: 'keyName' },
|
||||
{ label: 'i18n.translate', prop: 'translate' },
|
||||
{ label: 'i18n.languageSummary', prop: 'languageSummary' },
|
||||
{ label: 'i18n.languageName', prop: 'languageName' },
|
||||
{ label: 'i18n.parentKeyName', prop: 'parentKeyName' },
|
||||
{ label: 'table.operation', prop: 'operation', slot: 'operation' },
|
||||
];
|
||||
|
||||
// 添加多语言表单规则
|
|
@ -0,0 +1,125 @@
|
|||
import { reactive, ref } from 'vue';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { messageBox } from '@/utils/message';
|
||||
|
||||
export const addDialogVisible = ref(false);
|
||||
export const updateDialogVisible = ref(false);
|
||||
|
||||
const i18nStore = userI18nStore();
|
||||
// 更新表单数据
|
||||
export const updateForm = reactive({
|
||||
id: '',
|
||||
languageId: '',
|
||||
keyName: '',
|
||||
translate: '',
|
||||
parentId: '',
|
||||
});
|
||||
// 彻底删除 id列表
|
||||
const ids = ref<string[]>([]);
|
||||
|
||||
/**
|
||||
* * 查询内容
|
||||
*/
|
||||
export const getI18nDataList = async () => {
|
||||
i18nStore.loading = true;
|
||||
await i18nStore.getI18nMangeList();
|
||||
i18nStore.loading = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当前页改变时
|
||||
*/
|
||||
export const onCurrentPageChange = async (value: number) => {
|
||||
i18nStore.pagination.currentPage = value;
|
||||
await getI18nDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当分页发生变化
|
||||
* @param value
|
||||
*/
|
||||
export const onPageSizeChange = async (value: number) => {
|
||||
i18nStore.pagination.pageSize = value;
|
||||
await getI18nDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 选择框点击的行
|
||||
* @param row
|
||||
*/
|
||||
export const onSelectionChange = (row: any) => {
|
||||
ids.value = row.map((item: any) => item.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 行内容添加
|
||||
* 打开添加弹窗
|
||||
*/
|
||||
export const onRowAdd = () => {
|
||||
addDialogVisible.value = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 批量彻底删除行
|
||||
*/
|
||||
export const onRowDelete = async () => {
|
||||
const isConfirm = await messageBox({
|
||||
message: '是否确认批量删除(此操作不可逆)',
|
||||
title: '删除警告',
|
||||
showMessage: false,
|
||||
confirmMessage: '删除成功',
|
||||
cancelMessage: '取消删除',
|
||||
});
|
||||
|
||||
if (isConfirm) {
|
||||
const data = ids.value;
|
||||
await i18nStore.deleteI18n(data);
|
||||
await getI18nDataList();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* * 批量彻底删除行
|
||||
*/
|
||||
export const onRowDeleteWithChildren = async () => {
|
||||
const isConfirm = await messageBox({
|
||||
message: '是否确认批量删除(此操作不可逆)',
|
||||
title: '删除警告',
|
||||
showMessage: false,
|
||||
confirmMessage: '删除成功',
|
||||
cancelMessage: '取消删除',
|
||||
});
|
||||
|
||||
if (isConfirm) {
|
||||
const data = ids.value;
|
||||
await i18nStore.deleteI18n(data);
|
||||
await getI18nDataList();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当表格修改时
|
||||
*/
|
||||
export const onUpdate = (row: any) => {
|
||||
const data = row.row;
|
||||
|
||||
// 赋值内容
|
||||
updateForm.id = data.id;
|
||||
updateForm.languageId = data.parentKeyName;
|
||||
updateForm.keyName = data.keyName;
|
||||
updateForm.translate = data.translate;
|
||||
data.parentId != 0 && (updateForm.parentId = data.parentId);
|
||||
|
||||
// 打开弹窗
|
||||
updateDialogVisible.value = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当删除时
|
||||
* @param row
|
||||
*/
|
||||
export const onDelete = async (row: any) => {
|
||||
const id = row.row.id;
|
||||
const form = { id };
|
||||
await i18nStore.deleteI18n(form);
|
||||
await i18nStore.getI18nMangeList();
|
||||
};
|
|
@ -1,17 +1,18 @@
|
|||
<script lang="ts" setup>
|
||||
import SimpleDialog from '@/components/Dialog/SimpleDialog.vue';
|
||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
import SimpleDialog from '@/components/BaseDialog/SimpleDialog.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { addRules } from '@/views/i18n/language-type-setting/utils/rules';
|
||||
import { addRules } from '@/views/i18n/i18n-type-setting/utils/rules';
|
||||
import { isDefaultOptions } from '@/enums/baseConstant';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const i18nTypeStore = useI18nTypeStore();
|
||||
const i18nStore = userI18nStore();
|
||||
const form = reactive({
|
||||
languageName: '',
|
||||
summary: '',
|
||||
isDefalut: false,
|
||||
isDefault: false,
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -22,9 +23,9 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
|||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
await i18nTypeStore.addLanguageType(form);
|
||||
await i18nTypeStore.getLanguageType();
|
||||
i18nTypeStore.isAddShown = false;
|
||||
await i18nStore.addI18nType(form);
|
||||
await i18nStore.getI18nTypeList();
|
||||
i18nStore.isAddShown = false;
|
||||
} else {
|
||||
ElMessage.warning('请填写必填项');
|
||||
}
|
||||
|
@ -44,12 +45,12 @@ const resetForm = (formEl: FormInstance | undefined) => {
|
|||
* * 关闭弹窗
|
||||
*/
|
||||
const onCancel = (value: boolean) => {
|
||||
i18nTypeStore.isAddShown = value;
|
||||
i18nStore.isAddShown = value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SimpleDialog :show="i18nTypeStore.isAddShown" width="600" @on-cancel="onCancel">
|
||||
<SimpleDialog :show="i18nStore.isAddShown" width="600" @on-cancel="onCancel">
|
||||
<template #header>
|
||||
<h1>添加多语言种类</h1>
|
||||
</template>
|
||||
|
@ -62,7 +63,7 @@ const onCancel = (value: boolean) => {
|
|||
<el-input v-model="form.summary" autocomplete="off" type="text" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否为默认语言" prop="isDefault">
|
||||
<el-select v-model="form.isDefalut" placeholder="选择是否为默认">
|
||||
<el-select v-model="form.isDefault" placeholder="选择是否为默认">
|
||||
<el-option v-for="(item, index) in isDefaultOptions" :key="index" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
|
@ -0,0 +1,97 @@
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { columns } from '@/views/i18n/i18n-type-setting/utils/columns';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { messageBox } from '@/utils/message';
|
||||
import { addDialogVisible, getI18nDataList, onDelete } from '@/views/i18n/i18n-setting/utils/hook';
|
||||
import PureTableBar from '@/components/TableBar/src/bar';
|
||||
import { useRenderIcon } from '@/components/ReIcon/src/hooks';
|
||||
import AddFill from '@iconify-icons/ri/add-circle-line';
|
||||
import EditPen from '@iconify-icons/ep/edit-pen';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import Delete from '@iconify-icons/ep/delete';
|
||||
import PureTable from '@pureadmin/table';
|
||||
import AddI18nType from '@/views/i18n/i18n-type-setting/add-i18n-type.vue';
|
||||
|
||||
const i18nStore = userI18nStore();
|
||||
const tableRef = ref();
|
||||
|
||||
/**
|
||||
* * 获取多语言类型
|
||||
*/
|
||||
const getI18nType = () => {
|
||||
i18nStore.getI18nTypeList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 表格的列添加语言类型
|
||||
*/
|
||||
const onColumnAdd = () => {
|
||||
i18nStore.isAddShown = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 删除多语言类容
|
||||
*/
|
||||
const onColumnDelete = async (row: any, isPhysicalDelete: boolean) => {
|
||||
const id = row.id;
|
||||
const title = isPhysicalDelete ? '删除不可逆!' : '确认删除吗?';
|
||||
|
||||
messageBox({
|
||||
message: `删除这条 【${row.summary}】 `,
|
||||
title,
|
||||
showMessage: false,
|
||||
confirmMessage: undefined,
|
||||
cancelMessage: '取消删除',
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
i18nStore.deleteI18nType(id);
|
||||
}
|
||||
return result;
|
||||
})
|
||||
.then(result => result && getI18nType());
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getI18nType();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main">
|
||||
<!-- 添加多语言种类 -->
|
||||
<add-I18n-type />
|
||||
<PureTableBar :columns="columns" :tableRef="tableRef?.getTableRef()" title="多语言类型管理" @fullscreen="tableRef.setAdaptive()" @refresh="getI18nDataList">
|
||||
<template #buttons>
|
||||
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="addDialogVisible = true"> 添加多语言 </el-button>
|
||||
</template>
|
||||
<template v-slot="{ size, dynamicColumns }">
|
||||
<pure-table
|
||||
ref="tableRef"
|
||||
:adaptiveConfig="{ offsetBottom: 45 }"
|
||||
:columns="dynamicColumns"
|
||||
:data="i18nStore.i18nDataList"
|
||||
:header-cell-style="{ background: 'var(--el-fill-color-light)', color: 'var(--el-text-color-primary)' }"
|
||||
:loading="i18nStore.loading"
|
||||
:size="size"
|
||||
adaptive
|
||||
align-whole="center"
|
||||
row-key="id"
|
||||
showOverflowTooltip
|
||||
table-layout="auto"
|
||||
>
|
||||
<template #operation="{ row }">
|
||||
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary"> 修改 </el-button>
|
||||
<el-button v-show="row.menuType !== 3" :icon="useRenderIcon(AddFill)" :size="size" class="reset-margin" link type="primary"> 新增 </el-button>
|
||||
<el-popconfirm :title="`是否确认删除菜单名称为${$t(row.title)}的这条数据${row?.children?.length > 0 ? '注意下级菜单也会一并删除,请谨慎操作' : ''}`" @confirm="onDelete(row)">
|
||||
<template #reference>
|
||||
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</pure-table>
|
||||
</template>
|
||||
</PureTableBar>
|
||||
</div>
|
||||
</template>
|
|
@ -1,37 +1,36 @@
|
|||
import { ref } from 'vue';
|
||||
import { delObjectProperty } from '@pureadmin/utils';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
import { isDefaultOptions } from '@/enums/baseConstant';
|
||||
import TableIsDefaultTag from '@/components/Table/TableIsDefaultTag.vue';
|
||||
import TableIsDefaultTag from '@/components/TableBar/src/TableIsDefaultTag.vue';
|
||||
import { userI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
|
||||
const i18nTypeStore = useI18nTypeStore();
|
||||
const i18nTypeStore = userI18nTypeStore();
|
||||
export const editMap = ref({});
|
||||
|
||||
export const columns: TableColumnList = [
|
||||
{ type: 'index', label: '序号', width: 100 },
|
||||
// { type: 'index', label: '序号', width: 100 },
|
||||
{
|
||||
label: $t('i18n.languageName'),
|
||||
label: 'i18n.languageName',
|
||||
prop: 'languageName',
|
||||
cellRenderer({ row, index }) {
|
||||
return <>{editMap.value[index]?.editable ? <el-input v-model={row.languageName} /> : <p>{row.languageName}</p>}</>;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: $t('i18n.languageSummary'),
|
||||
label: 'i18n.languageSummary',
|
||||
prop: 'summary',
|
||||
cellRenderer({ row, index }) {
|
||||
return <>{editMap.value[index]?.editable ? <el-input v-model={row.summary} /> : <p>{row.summary}</p>}</>;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: $t('i18n.isDefault'),
|
||||
label: 'i18n.isDefault',
|
||||
prop: 'isDefault',
|
||||
cellRenderer({ row, index }) {
|
||||
return (
|
||||
<>
|
||||
{editMap.value[index]?.editable ? (
|
||||
<el-select placeholder={$t('table.chooseIsDefault')} v-model={row.isDefault}>
|
||||
<el-select placeholder={'table.chooseIsDefault'} v-model={row.isDefault}>
|
||||
{isDefaultOptions.map(item => (
|
||||
<el-option key={item.value} label={item.label} value={item.value} />
|
||||
))}
|
||||
|
@ -44,7 +43,7 @@ export const columns: TableColumnList = [
|
|||
},
|
||||
},
|
||||
// ? 表格操作
|
||||
{ label: $t('table.operation'), prop: 'op', slot: 'op', width: 160, fixed: 'right' },
|
||||
{ label: 'table.operation', prop: 'op', slot: 'op', width: 160, fixed: 'right' },
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -62,9 +61,9 @@ export function onEdit(row: any, index: number) {
|
|||
* @param index
|
||||
*/
|
||||
export async function onSave(row: any, index: number) {
|
||||
await i18nTypeStore.updateLanguageType(row);
|
||||
await i18nTypeStore.updateI18nType(row);
|
||||
editMap.value[index].editable = false;
|
||||
await i18nTypeStore.getLanguageType();
|
||||
await i18nTypeStore.getI18nTypeList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,5 +72,5 @@ export async function onSave(row: any, index: number) {
|
|||
*/
|
||||
export function onCancel(index: number) {
|
||||
editMap.value[index].editable = false;
|
||||
i18nTypeStore.dataList[index] = delObjectProperty(editMap.value[index], 'editable');
|
||||
i18nTypeStore.datalist[index] = delObjectProperty(editMap.value[index], 'editable');
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import TablePlusBar from '@/components/TableBar/src/TablePlusBar.vue';
|
||||
import { DeleteFilled, Plus } from '@element-plus/icons-vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { columns } from '@/views/i18n/language-setting/utils/columns';
|
||||
import { userI18nSettingStore } from '@/store/i18n/i18nSetting';
|
||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
import LanguageAdd from '@/views/i18n/language-setting/language-add.vue';
|
||||
import LanguageUpdate from '@/views/i18n/language-setting/language-update.vue';
|
||||
import { I18nSettingsRow, I18nSettingsUpdateForm } from '@/types/store/system/i18n/i18n-setting';
|
||||
import { messageBox } from '@/utils/message';
|
||||
|
||||
const i18nSettingStore = userI18nSettingStore();
|
||||
const i18nTypeStore = useI18nTypeStore();
|
||||
const column = ref(columns);
|
||||
// 更新表单数据
|
||||
const updateForm = reactive<I18nSettingsUpdateForm>({
|
||||
id: '',
|
||||
languageId: '',
|
||||
keyName: '',
|
||||
translate: '',
|
||||
parentId: '',
|
||||
});
|
||||
// 彻底删除 id列表
|
||||
const ids = ref<string[]>([]);
|
||||
|
||||
/**
|
||||
* * 查询内容
|
||||
*/
|
||||
const getI18nDataList = async () => {
|
||||
i18nSettingStore.loading = true;
|
||||
await i18nSettingStore.getQueryI18nPage();
|
||||
i18nSettingStore.loading = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当前页改变时
|
||||
*/
|
||||
const onCurrentPageChange = async (value: number) => {
|
||||
i18nSettingStore.pagination.currentPage = value;
|
||||
await getI18nDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当分页发生变化
|
||||
* @param value
|
||||
*/
|
||||
const onPageSizeChange = (value: number) => {
|
||||
i18nSettingStore.pagination.pageSize = value;
|
||||
getI18nDataList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 选择框点击的行
|
||||
* @param row
|
||||
*/
|
||||
const onSelectionChange = (row: I18nSettingsRow[]) => {
|
||||
ids.value = row.map(item => item.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* * 行内容添加
|
||||
* 打开添加弹窗
|
||||
*/
|
||||
const onRowAdd = () => {
|
||||
i18nSettingStore.addDialogVisible = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 批量彻底删除行
|
||||
*/
|
||||
const onRowDelete = async () => {
|
||||
const isConfirm = await messageBox({
|
||||
message: '是否确认批量删除(此操作不可逆)',
|
||||
title: '删除警告',
|
||||
showMessage: false,
|
||||
confirmMessage: '删除成功',
|
||||
cancelMessage: '取消删除',
|
||||
});
|
||||
|
||||
if (isConfirm) {
|
||||
const data = ids.value;
|
||||
await i18nSettingStore.deleteI18nByIds(data);
|
||||
await getI18nDataList();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* * 批量彻底删除行
|
||||
*/
|
||||
const onRowDeleteWithChildren = async () => {
|
||||
const isConfirm = await messageBox({
|
||||
message: '是否确认批量删除(此操作不可逆)',
|
||||
title: '删除警告',
|
||||
showMessage: false,
|
||||
confirmMessage: '删除成功',
|
||||
cancelMessage: '取消删除',
|
||||
});
|
||||
|
||||
if (isConfirm) {
|
||||
const data = ids.value;
|
||||
await i18nSettingStore.deleteI18nByIdsWithChildren(data);
|
||||
await getI18nDataList();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当表格修改时
|
||||
*/
|
||||
const onUpdate = (row: any) => {
|
||||
const data = row.row;
|
||||
// 根据语言key找到语言id
|
||||
const languageTypeMap = i18nTypeStore.languageTypeMap.filter(item => item.key == data.languageName);
|
||||
// 赋值内容
|
||||
updateForm.id = data.id;
|
||||
updateForm.languageId = data.parentKeyName;
|
||||
updateForm.keyName = data.keyName;
|
||||
updateForm.translate = data.translate;
|
||||
data.parentId != 0 && (updateForm.parentId = data.parentId);
|
||||
updateForm.languageId = languageTypeMap[0].id;
|
||||
|
||||
// 打开弹窗
|
||||
i18nSettingStore.updateDialogVisible = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 当删除时
|
||||
* @param row
|
||||
*/
|
||||
const onDelete = async (row: any) => {
|
||||
const id = row.row.id;
|
||||
const form = { id };
|
||||
await i18nSettingStore.deleteI18n(form);
|
||||
await i18nSettingStore.getQueryI18nPage();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getI18nDataList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-between">
|
||||
<language-add v-if="i18nSettingStore.addDialogVisible" />
|
||||
<language-update v-if="i18nSettingStore.updateDialogVisible" :form="updateForm" />
|
||||
<TablePlusBar
|
||||
:column="column"
|
||||
:data-list="i18nSettingStore.dataList"
|
||||
:handle-current-change="onCurrentPageChange"
|
||||
:handle-selection-change="onSelectionChange"
|
||||
:handle-size-change="onPageSizeChange"
|
||||
:loading="i18nSettingStore.loading"
|
||||
:model="i18nSettingStore.form"
|
||||
:on-re-fresh="getI18nDataList"
|
||||
:on-search="getI18nDataList"
|
||||
:pagination="i18nSettingStore.pagination"
|
||||
:table-delete="onDelete"
|
||||
:table-edit="onUpdate"
|
||||
class="flex-1"
|
||||
@change-column="args => (column = args)"
|
||||
>
|
||||
<template #tableForm>
|
||||
<el-form-item label="多语言key" prop="keyName">
|
||||
<el-input v-model="i18nSettingStore.form.keyName" class="!w-[150px]" clearable placeholder="输入多语言key" />
|
||||
</el-form-item>
|
||||
<el-form-item label="翻译" prop="translate">
|
||||
<el-input v-model="i18nSettingStore.form.translate" class="!w-[150px]" clearable placeholder="输入多语言翻译" />
|
||||
</el-form-item>
|
||||
<el-form-item label="语言名称" prop="languageName" style="width: 240px">
|
||||
<el-select v-model="i18nSettingStore.form.languageName" filterable placeholder="选择语言名称">
|
||||
<el-option v-for="item in i18nTypeStore.languageTypeMap" :key="item.id" :label="item.value" :value="item.key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<template #tableButtons>
|
||||
<el-button :icon="Plus" type="primary" @click="onRowAdd">{{ $t('buttons.add') }}</el-button>
|
||||
<el-button v-show="ids.length > 0" :icon="DeleteFilled" type="danger" @click="onRowDelete">
|
||||
{{ $t('buttons.deleteBatches') }}
|
||||
</el-button>
|
||||
<el-button v-show="ids.length > 0" :icon="DeleteFilled" type="danger" @click="onRowDeleteWithChildren"> 彻底删除(包含删除子级内容) </el-button>
|
||||
</template>
|
||||
</TablePlusBar>
|
||||
</div>
|
||||
</template>
|
|
@ -1,89 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import LanguageDialog from '@/views/i18n/language-setting/language-dialog.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { userI18nSettingStore } from '@/store/i18n/i18nSetting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { I18nSettingsAddForm } from '@/types/store/system/i18n/i18n-setting';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
|
||||
const i18nSettingStore = userI18nSettingStore();
|
||||
const i18nStore = userI18nStore();
|
||||
const { addDialogVisible } = storeToRefs(i18nSettingStore);
|
||||
const dialogRef = ref();
|
||||
const form = reactive<I18nSettingsAddForm>({
|
||||
languageId: '',
|
||||
keyName: '',
|
||||
translate: '',
|
||||
parentId: '',
|
||||
});
|
||||
|
||||
/**
|
||||
* * 获取多语言所有父级内容
|
||||
*/
|
||||
const getLanguageAllParentList = () => {
|
||||
i18nStore.getLanguageAllParentList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 关闭弹窗
|
||||
*/
|
||||
const onClose = () => {
|
||||
i18nSettingStore.addDialogVisible = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 添加内容
|
||||
*/
|
||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await i18nSettingStore.addLanguage(form);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
i18nSettingStore.addDialogVisible = false;
|
||||
await i18nSettingStore.getQueryI18nPage();
|
||||
} else {
|
||||
ElMessage.closeAll();
|
||||
ElMessage.warning($t('status.requiredFields'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* * 继续添加内容
|
||||
*/
|
||||
const onAddContinue = (value: any) => {
|
||||
const formEl: FormInstance | undefined = value.ruleFormRef;
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await i18nSettingStore.addLanguage(form);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
await i18nSettingStore.getQueryI18nPage();
|
||||
} else {
|
||||
ElMessage.closeAll();
|
||||
ElMessage.warning($t('status.requiredFields'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getLanguageAllParentList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<language-dialog ref="dialogRef" :form="form" :on-close="onClose" :on-submit="onSubmit" :visible="addDialogVisible" title="添加多语言内容">
|
||||
<template #footer>
|
||||
<el-button type="success" @click="onAddContinue(dialogRef)">继续添加</el-button>
|
||||
</template>
|
||||
</language-dialog>
|
||||
</template>
|
|
@ -1,61 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import { userI18nSettingStore } from '@/store/i18n/i18nSetting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { onMounted } from 'vue';
|
||||
import LanguageDialog from '@/views/i18n/language-setting/language-dialog.vue';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { I18nSettingsUpdateForm } from '@/types/store/system/i18n/i18n-setting';
|
||||
import { userI18nStore } from '@/store/i18n/i18n';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
|
||||
const props = defineProps({
|
||||
form: { type: Object as PropType<I18nSettingsUpdateForm> },
|
||||
});
|
||||
|
||||
const i18nSettingStore = userI18nSettingStore();
|
||||
const i18nStore = userI18nStore();
|
||||
const { updateDialogVisible } = storeToRefs(i18nSettingStore);
|
||||
|
||||
/**
|
||||
* * 获取多语言所有父级内容
|
||||
*/
|
||||
const getLanguageAllParentList = () => {
|
||||
i18nStore.getLanguageAllParentList();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 关闭弹窗
|
||||
*/
|
||||
const onClose = () => {
|
||||
i18nSettingStore.updateDialogVisible = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 添加内容
|
||||
*/
|
||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async valid => {
|
||||
if (valid) {
|
||||
// 添加内容
|
||||
const result = await i18nSettingStore.updateLanguage(props.form);
|
||||
if (!result) return false;
|
||||
|
||||
// 添加成功后刷新数据
|
||||
i18nSettingStore.updateDialogVisible = false;
|
||||
await i18nSettingStore.getQueryI18nPage();
|
||||
} else {
|
||||
ElMessage.closeAll();
|
||||
ElMessage.warning($t('status.requiredFields'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getLanguageAllParentList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<language-dialog :form="form" :on-close="onClose" :on-submit="onSubmit" :visible="updateDialogVisible" title="修改多语言内容" />
|
||||
</template>
|
|
@ -1,101 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import TablePlusBar from '@/components/TableBar/src/TablePlusBar.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { columns, editMap, onCancel, onEdit, onSave } from '@/views/i18n/language-type-setting/utils/columns';
|
||||
import { DeleteFilled, EditPen, Plus } from '@element-plus/icons-vue';
|
||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
||||
import { messageBox } from '@/utils/message';
|
||||
import AddLanguageType from '@/views/i18n/language-type-setting/add-language-tyoe.vue';
|
||||
|
||||
const column = ref(columns);
|
||||
const i18nTypeStore = useI18nTypeStore();
|
||||
|
||||
/**
|
||||
* * 获取多语言类型
|
||||
*/
|
||||
const getLanguageType = () => {
|
||||
i18nTypeStore.getLanguageType();
|
||||
};
|
||||
|
||||
/**
|
||||
* * 表格的列添加语言类型
|
||||
*/
|
||||
const onColumnAdd = () => {
|
||||
i18nTypeStore.isAddShown = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* * 删除多语言类容
|
||||
*/
|
||||
const onColumnDelete = async (row: any, isPhysicalDelete: boolean) => {
|
||||
const id = row.id;
|
||||
const title = isPhysicalDelete ? '物理删除不可逆!' : '确认删除吗?';
|
||||
|
||||
messageBox({
|
||||
message: `删除这条 【${row.summary}】 `,
|
||||
title,
|
||||
showMessage: false,
|
||||
confirmMessage: undefined,
|
||||
cancelMessage: '取消删除',
|
||||
})
|
||||
.then(result => {
|
||||
if (result) {
|
||||
// 物理删除
|
||||
isPhysicalDelete && i18nTypeStore.removeLanguageType(id);
|
||||
// 逻辑删除
|
||||
!isPhysicalDelete && i18nTypeStore.deleteLanguageType(id);
|
||||
}
|
||||
return result;
|
||||
})
|
||||
.then(result => result && getLanguageType());
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getLanguageType();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- 添加多语言种类 -->
|
||||
<add-language-type />
|
||||
<TablePlusBar
|
||||
:column="column"
|
||||
:data-list="i18nTypeStore.dataList"
|
||||
:loading="i18nTypeStore.loading"
|
||||
:on-re-fresh="getLanguageType"
|
||||
:table-delete="onColumnDelete"
|
||||
:table-query-form-visible="false"
|
||||
@changeColumn="args => (column = args)"
|
||||
>
|
||||
<!-- 表格头部按钮 -->
|
||||
<template #tableButtons>
|
||||
<el-button :icon="Plus" type="primary" @click="onColumnAdd">{{ $t('buttons.add') }}</el-button>
|
||||
</template>
|
||||
|
||||
<template #op="{ row, index }">
|
||||
<div v-if="!editMap[index]?.editable" class="flex justify-around">
|
||||
<el-button :icon="EditPen" link type="warning" @click="onEdit(row, index)">修改</el-button>
|
||||
<el-dropdown :hide-on-click="false">
|
||||
<el-link :icon="DeleteFilled" :underline="false" type="danger"> 删除选项</el-link>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<el-button :icon="DeleteFilled" link type="warning" @click="onColumnDelete(row, false)">删除 </el-button>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-button :icon="DeleteFilled" link type="danger" @click="onColumnDelete(row, true)">彻底删除 </el-button>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<el-button class="reset-margin" link type="primary" @click="onSave(row, index)"> 保存</el-button>
|
||||
<el-button class="reset-margin" link @click="onCancel(index)"> 取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</TablePlusBar>
|
||||
</div>
|
||||
</template>
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import ReCol from '@/components/MyCol';
|
||||
import { formRules } from './utils/rule';
|
||||
import { FormProps } from './utils/types';
|
||||
|
@ -8,6 +8,7 @@ import Segmented from '@/components/ReSegmented';
|
|||
import ReAnimateSelector from '@/components/AnimateSelector';
|
||||
import { fixedTagOptions, frameLoadingOptions, hiddenTagOptions, keepAliveOptions, menuTypeOptions, showLinkOptions, showParentOptions } from '@/enums';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { userMenuIconStore } from '@/store/modules/menuIcon';
|
||||
|
||||
const props = withDefaults(defineProps<FormProps>(), {
|
||||
formInline: () => ({
|
||||
|
@ -33,9 +34,14 @@ const props = withDefaults(defineProps<FormProps>(), {
|
|||
}),
|
||||
});
|
||||
|
||||
const menuIconStore = userMenuIconStore();
|
||||
const ruleFormRef = ref();
|
||||
const newFormInline = ref(props.formInline);
|
||||
|
||||
onMounted(() => {
|
||||
menuIconStore.getMenuIconList();
|
||||
});
|
||||
|
||||
defineExpose({ menuFormRef: ruleFormRef });
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { $t } from '@/plugins/i18n';
|
||||
import { PureTableBar } from '@/components/TableBar';
|
||||
import PureTableBar from '@/components/TableBar/src/bar';
|
||||
import { useRenderIcon } from '@/components/ReIcon/src/hooks';
|
||||
import Delete from '@iconify-icons/ep/delete';
|
||||
import EditPen from '@iconify-icons/ep/edit-pen';
|
||||
import Refresh from '@iconify-icons/ep/refresh';
|
||||
import AddFill from '@iconify-icons/ri/add-circle-line';
|
||||
import { dataList, handleDelete, handleSelectionChange, loading, onSearch, openDialog, resetForm } from '@/views/menu/utils/hook';
|
||||
import { dataList, handleDelete, loading, onSearch, openDialog, resetForm } from '@/views/menu/utils/hook';
|
||||
import form from '@/views/role/form.vue';
|
||||
import PureTable from '@pureadmin/table';
|
||||
import { columns } from '@/views/menu/utils/rule';
|
||||
|
@ -36,7 +36,7 @@ onMounted(() => {
|
|||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<PureTableBar :columns="columns" :isExpandAll="false" :tableRef="tableRef?.getTableRef()" title="菜单管理(仅演示,操作后不生效)" @fullscreen="tableRef.value.setAdaptive()" @refresh="onSearch">
|
||||
<PureTableBar :columns="columns" :isExpandAll="false" :tableRef="tableRef?.getTableRef()" title="菜单管理" @fullscreen="tableRef.setAdaptive()" @refresh="onSearch">
|
||||
<template #buttons>
|
||||
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="openDialog()"> 新增菜单</el-button>
|
||||
</template>
|
||||
|
@ -61,7 +61,7 @@ onMounted(() => {
|
|||
<el-button v-show="row.menuType !== 3" :icon="useRenderIcon(AddFill)" :size="size" class="reset-margin" link type="primary" @click="openDialog('新增', { parentId: row.id } as any)">
|
||||
新增
|
||||
</el-button>
|
||||
<el-popconfirm :title="`是否确认删除菜单名称为${$t(row.title)}的这条数据${row?.children?.length > 0 ? '。注意下级菜单也会一并删除,请谨慎操作' : ''}`" @confirm="handleDelete(row)">
|
||||
<el-popconfirm :title="`是否确认删除菜单名称为${$t(row.title)}的这条数据${row?.children?.length > 0 ? '注意下级菜单也会一并删除,请谨慎操作' : ''}`" @confirm="handleDelete(row)">
|
||||
<template #reference>
|
||||
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
|
||||
</template>
|
||||
|
|
|
@ -34,14 +34,6 @@ export const getMenuType = (type, text = false) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 表格选择
|
||||
* @param val
|
||||
*/
|
||||
export const handleSelectionChange = val => {
|
||||
console.log('handleSelectionChange', val);
|
||||
};
|
||||
|
||||
/**
|
||||
* 表单重置
|
||||
* @param formEl
|
||||
|
@ -52,6 +44,10 @@ export const resetForm = async formEl => {
|
|||
await onSearch();
|
||||
};
|
||||
|
||||
export const handleSelectionChange = (val: any) => {
|
||||
console.log('handleSelectionChange', val);
|
||||
};
|
||||
|
||||
export const onSearch = async () => {
|
||||
loading.value = true;
|
||||
|
||||
|
|
Loading…
Reference in New Issue