page: 📄 多语言页面待完成
This commit is contained in:
parent
024188ee3d
commit
1d98efe92e
|
@ -7,6 +7,17 @@ export interface BaseResult<T> {
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ResultTable {
|
||||||
|
/** 列表数据 */
|
||||||
|
list: Array<any>;
|
||||||
|
/** 总条目数 */
|
||||||
|
total?: number;
|
||||||
|
/** 每页显示条目个数 */
|
||||||
|
pageSize?: number;
|
||||||
|
/** 当前页数 */
|
||||||
|
pageNo?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export type resultType = {
|
export type resultType = {
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,65 @@
|
||||||
import { http } from '@/api/service/mockRequest';
|
import { http } from '@/api/service/mockRequest';
|
||||||
import type { Result } from '@/types/store/baseStoreState';
|
import type { BaseResult } from '@/api/service/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 获取多语言内容
|
* * 获取多语言内容
|
||||||
*/
|
*/
|
||||||
export const fetchGetI18n = () => {
|
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 { http } from '@/api/service/request';
|
||||||
import type { BaseResult } from '@/api/service/types';
|
import type { BaseResult, ResultTable } from '@/api/service/types';
|
||||||
|
|
||||||
type ResultTable = {
|
|
||||||
/** 列表数据 */
|
|
||||||
list: Array<any>;
|
|
||||||
/** 总条目数 */
|
|
||||||
total?: number;
|
|
||||||
/** 每页显示条目个数 */
|
|
||||||
pageSize?: number;
|
|
||||||
/** 当前页数 */
|
|
||||||
pageNo?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 系统管理-用户路由获取 */
|
/** 系统管理-用户路由获取 */
|
||||||
export const getRouterAsync = () => {
|
export const getRouterAsync = () => {
|
||||||
return http.request<BaseResult<any>>('get', 'router/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) => {
|
export const getMenuList = (data?: any) => {
|
||||||
return http.request<BaseResult<ResultTable>>('get', `router/getMenus`, { data });
|
return http.request<BaseResult<ResultTable>>('get', `router/getMenus`, { data });
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 系统管理-添加菜单 */
|
/** 菜单管理-添加菜单 */
|
||||||
export const addMenu = (data?: any) => {
|
export const addMenu = (data?: any) => {
|
||||||
return http.request<BaseResult<any>>('post', `router/addMenu`, { data });
|
return http.request<BaseResult<any>>('post', `router/addMenu`, { data });
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 系统管理-更新菜单 */
|
/** 菜单管理-更新菜单 */
|
||||||
export const updateMenu = (data?: any) => {
|
export const updateMenu = (data?: any) => {
|
||||||
return http.request<BaseResult<any>>('put', `router/updateMenu`, { data });
|
return http.request<BaseResult<any>>('put', `router/updateMenu`, { data });
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 系统管理-删除菜单 */
|
/** 菜单管理-删除菜单 */
|
||||||
export const deletedMenuByIds = (data?: any) => {
|
export const deletedMenuByIds = (data?: any) => {
|
||||||
return http.request<BaseResult<any>>('delete', `router/deletedMenuByIds`, { data });
|
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,268 +1,62 @@
|
||||||
<script setup lang="ts">
|
<script lang="ts" setup>
|
||||||
import { IconJson } from "@/components/ReIcon/data";
|
import LocalSelect from '@/components/ReIcon/src/LocalSelect.vue';
|
||||||
import { cloneDeep, isAllEmpty } from "@pureadmin/utils";
|
import { inputValue } from '@/components/ReIcon/src/hooks';
|
||||||
import { ref, computed, CSSProperties, watch } from "vue";
|
|
||||||
import Search from "@iconify-icons/ri/search-eye-line";
|
|
||||||
|
|
||||||
type ParameterCSSProperties = (item?: string) => CSSProperties | undefined;
|
|
||||||
|
|
||||||
defineOptions({
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="selector">
|
<div class="selector">
|
||||||
<el-input v-model="inputValue" disabled>
|
<el-input v-model="inputValue" disabled>
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-popover
|
<LocalSelect />
|
||||||
:width="350"
|
</template>
|
||||||
trigger="click"
|
</el-input>
|
||||||
popper-class="pure-popper"
|
</div>
|
||||||
: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>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<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) {
|
:deep(.el-tabs__nav-next) {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
box-shadow: -5px 0 5px -6px #ccc;
|
box-shadow: -5px 0 5px -6px #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__nav-prev) {
|
:deep(.el-tabs__nav-prev) {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
box-shadow: 5px 0 5px -6px #ccc;
|
box-shadow: 5px 0 5px -6px #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-input-group__append) {
|
:deep(.el-input-group__append) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__item) {
|
:deep(.el-tabs__item) {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__header),
|
:deep(.el-tabs__header),
|
||||||
:deep(.el-tabs__nav-wrap) {
|
:deep(.el-tabs__nav-wrap) {
|
||||||
position: static;
|
position: static;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
box-shadow: 0 2px 5px rgb(0 0 0 / 6%);
|
box-shadow: 0 2px 5px rgb(0 0 0 / 6%);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__nav-wrap::after) {
|
:deep(.el-tabs__nav-wrap::after) {
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__nav-wrap) {
|
:deep(.el-tabs__nav-wrap) {
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-tabs__content) {
|
:deep(.el-tabs__content) {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import type { iconType } from "./types";
|
import type { iconType } from './types';
|
||||||
import { h, defineComponent, type Component } from "vue";
|
import { type Component, defineComponent, h, ref } from 'vue';
|
||||||
import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
|
import { FontIcon, IconifyIconOffline, IconifyIconOnline } from '../index';
|
||||||
|
|
||||||
|
export const inputValue = ref();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
|
* 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标
|
||||||
|
@ -10,52 +12,48 @@ import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index";
|
||||||
* @returns Component
|
* @returns Component
|
||||||
*/
|
*/
|
||||||
export function useRenderIcon(icon: any, attrs?: iconType): Component {
|
export function useRenderIcon(icon: any, attrs?: iconType): Component {
|
||||||
// iconfont
|
// iconfont
|
||||||
const ifReg = /^IF-/;
|
const ifReg = /^IF-/;
|
||||||
// typeof icon === "function" 属于SVG
|
// typeof icon === "function" 属于SVG
|
||||||
if (ifReg.test(icon)) {
|
if (ifReg.test(icon)) {
|
||||||
// iconfont
|
// iconfont
|
||||||
const name = icon.split(ifReg)[1];
|
const name = icon.split(ifReg)[1];
|
||||||
const iconName = name.slice(
|
const iconName = name.slice(0, name.indexOf(' ') == -1 ? name.length : name.indexOf(' '));
|
||||||
0,
|
const iconType = name.slice(name.indexOf(' ') + 1, name.length);
|
||||||
name.indexOf(" ") == -1 ? name.length : name.indexOf(" ")
|
return defineComponent({
|
||||||
);
|
name: 'FontIcon',
|
||||||
const iconType = name.slice(name.indexOf(" ") + 1, name.length);
|
render() {
|
||||||
return defineComponent({
|
return h(FontIcon, {
|
||||||
name: "FontIcon",
|
icon: iconName,
|
||||||
render() {
|
iconType,
|
||||||
return h(FontIcon, {
|
...attrs,
|
||||||
icon: iconName,
|
});
|
||||||
iconType,
|
},
|
||||||
...attrs
|
});
|
||||||
});
|
} else if (typeof icon === 'function' || typeof icon?.render === 'function') {
|
||||||
}
|
// svg
|
||||||
});
|
return attrs ? h(icon, { ...attrs }) : icon;
|
||||||
} else if (typeof icon === "function" || typeof icon?.render === "function") {
|
} else if (typeof icon === 'object') {
|
||||||
// svg
|
return defineComponent({
|
||||||
return attrs ? h(icon, { ...attrs }) : icon;
|
name: 'OfflineIcon',
|
||||||
} else if (typeof icon === "object") {
|
render() {
|
||||||
return defineComponent({
|
return h(IconifyIconOffline, {
|
||||||
name: "OfflineIcon",
|
icon: icon,
|
||||||
render() {
|
...attrs,
|
||||||
return h(IconifyIconOffline, {
|
});
|
||||||
icon: icon,
|
},
|
||||||
...attrs
|
});
|
||||||
});
|
} else {
|
||||||
}
|
// 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之
|
||||||
});
|
return defineComponent({
|
||||||
} else {
|
name: 'Icon',
|
||||||
// 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之
|
render() {
|
||||||
return defineComponent({
|
const IconifyIcon = icon && icon.includes(':') ? IconifyIconOnline : IconifyIconOffline;
|
||||||
name: "Icon",
|
return h(IconifyIcon, {
|
||||||
render() {
|
icon: icon,
|
||||||
const IconifyIcon =
|
...attrs,
|
||||||
icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline;
|
});
|
||||||
return h(IconifyIcon, {
|
},
|
||||||
icon: icon,
|
});
|
||||||
...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,95 +1,82 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { getCurrentInstance, nextTick, onMounted, PropType, ref, unref, watch } from 'vue';
|
||||||
getCurrentInstance,
|
import { rendTipProps } from '@/components/TableBar/utils/tableConfig';
|
||||||
nextTick,
|
import { cellHeaderStyle, getDropdownItemStyle, iconClass, topClass } from '@/components/TableBar/utils/tableStyle';
|
||||||
onMounted,
|
import PureTable from '@pureadmin/table';
|
||||||
PropType,
|
import { useRoute } from 'vue-router';
|
||||||
ref,
|
import { useI18n } from 'vue-i18n';
|
||||||
unref,
|
import RefreshIcon from '@/assets/table-bar/refresh.svg?component';
|
||||||
watch
|
import CollapseIcon from '@/assets/table-bar/collapse.svg?component';
|
||||||
} from "vue";
|
import SettingIcon from '@/assets/table-bar/settings.svg?component';
|
||||||
import { rendTipProps } from "@/components/TableBar/utils/tableConfig";
|
import { cloneDeep, getKeyList, isBoolean, isFunction } from '@pureadmin/utils';
|
||||||
import {
|
import DragIcon from '@/assets/table-bar/drag.svg?component';
|
||||||
cellHeaderStyle,
|
import Sortable from 'sortablejs';
|
||||||
getDropdownItemStyle,
|
import { $t } from '@/plugins/i18n';
|
||||||
iconClass,
|
import { DeleteFilled, EditPen } from '@element-plus/icons-vue';
|
||||||
topClass
|
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
|
||||||
} from "@/components/TableBar/utils/tableStyle";
|
import Refresh from '@iconify-icons/ep/refresh';
|
||||||
import PureTable from "@pureadmin/table";
|
import { FormInstance } from 'element-plus';
|
||||||
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({
|
const props = defineProps({
|
||||||
// 表格数据
|
// 表格数据
|
||||||
dataList: { type: Array<any>, default: [] },
|
dataList: { type: Array<any>, default: [] },
|
||||||
// 表格列字段
|
// 表格列字段
|
||||||
column: { type: Array as PropType<any>, default: () => [] },
|
column: { type: Array as PropType<any>, default: () => [] },
|
||||||
// 是否加载
|
// 是否加载
|
||||||
loading: { type: Boolean, default: false },
|
loading: { type: Boolean, default: false },
|
||||||
// 表格头部查询
|
// 表格头部查询
|
||||||
tableQueryFormVisible: { type: Boolean, default: true },
|
tableQueryFormVisible: { type: Boolean, default: true },
|
||||||
// 页面字体大小,small | default | large
|
// 页面字体大小,small | default | large
|
||||||
size: { type: String as PropType<any>, default: "default" },
|
size: { type: String as PropType<any>, default: 'default' },
|
||||||
// 分页器参数
|
// 分页器参数
|
||||||
pagination: { type: Object, default: Object },
|
pagination: { type: Object, default: Object },
|
||||||
// 选择行发生变化
|
// 选择行发生变化
|
||||||
handleSelectionChange: {
|
handleSelectionChange: {
|
||||||
type: Function as PropType<Function>,
|
type: Function as PropType<Function>,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
},
|
},
|
||||||
// 分页大小变化
|
// 分页大小变化
|
||||||
handleSizeChange: {
|
handleSizeChange: {
|
||||||
type: Function as PropType<Function>,
|
type: Function as PropType<Function>,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
},
|
},
|
||||||
// 当前页变化
|
// 当前页变化
|
||||||
handleCurrentChange: {
|
handleCurrentChange: {
|
||||||
type: Function as PropType<Function>,
|
type: Function as PropType<Function>,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
},
|
},
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {
|
form: {
|
||||||
type: Object as PropType<any>,
|
type: Object as PropType<any>,
|
||||||
default: Object
|
default: Object,
|
||||||
},
|
},
|
||||||
// 表格的key值
|
// 表格的key值
|
||||||
tableKey: {
|
tableKey: {
|
||||||
type: [String, Number] as PropType<string | number>,
|
type: [String, Number] as PropType<string | number>,
|
||||||
default: "0"
|
default: '0',
|
||||||
},
|
},
|
||||||
// 表格标题
|
// 表格标题
|
||||||
tableTitle: { type: String, default: "" },
|
tableTitle: { type: String, default: '' },
|
||||||
// 表格修改
|
// 表格修改
|
||||||
tableEdit: {
|
tableEdit: {
|
||||||
type: Function as PropType<Function>,
|
type: Function as PropType<Function>,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
}, // 表格删除
|
}, // 表格删除
|
||||||
tableDelete: {
|
tableDelete: {
|
||||||
type: Function as PropType<Function>,
|
type: Function as PropType<Function>,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
},
|
},
|
||||||
// 刷新时
|
// 刷新时
|
||||||
onReFresh: {
|
onReFresh: {
|
||||||
type: Function as PropType<Function>,
|
type: Function as PropType<Function>,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
},
|
},
|
||||||
onSearch: { type: Function as PropType<any> },
|
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 { t, locale } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
// 是否全选
|
// 是否全选
|
||||||
|
@ -100,16 +87,10 @@ const isIndeterminate = ref(false);
|
||||||
// 动态行
|
// 动态行
|
||||||
const dynamicColumns = ref(props.column);
|
const dynamicColumns = ref(props.column);
|
||||||
// 过滤是否选中的列
|
// 过滤是否选中的列
|
||||||
const filterColumns = cloneDeep(props.column).filter(column =>
|
const filterColumns = cloneDeep(props.column).filter(column => (isBoolean(column?.hide) ? !column.hide : !(isFunction(column?.hide) && column?.hide())));
|
||||||
isBoolean(column?.hide)
|
|
||||||
? !column.hide
|
|
||||||
: !(isFunction(column?.hide) && column?.hide())
|
|
||||||
);
|
|
||||||
// 选择当前列
|
// 选择当前列
|
||||||
const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), "label"));
|
const checkedColumns = ref(getKeyList(cloneDeep(filterColumns), 'label'));
|
||||||
const checkColumnList = ref(
|
const checkColumnList = ref(getKeyList(cloneDeep(dynamicColumns.value), 'label'));
|
||||||
getKeyList(cloneDeep(dynamicColumns.value), "label")
|
|
||||||
);
|
|
||||||
const instance = getCurrentInstance()!;
|
const instance = getCurrentInstance()!;
|
||||||
const ruleFormRef = ref<FormInstance>();
|
const ruleFormRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
@ -118,7 +99,7 @@ const ruleFormRef = ref<FormInstance>();
|
||||||
* @param value 修改样式大小 larger | default | small
|
* @param value 修改样式大小 larger | default | small
|
||||||
*/
|
*/
|
||||||
const handleTableSizeClick = (value: string) => {
|
const handleTableSizeClick = (value: string) => {
|
||||||
size.value = value;
|
size.value = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,11 +107,9 @@ const handleTableSizeClick = (value: string) => {
|
||||||
* @param val 是否全部显示
|
* @param val 是否全部显示
|
||||||
*/
|
*/
|
||||||
const handleCheckAllChange = (val: boolean) => {
|
const handleCheckAllChange = (val: boolean) => {
|
||||||
checkedColumns.value = val ? checkColumnList.value : [];
|
checkedColumns.value = val ? checkColumnList.value : [];
|
||||||
isIndeterminate.value = false;
|
isIndeterminate.value = false;
|
||||||
dynamicColumns.value.map(column =>
|
dynamicColumns.value.map(column => (val ? (column.hide = false) : (column.hide = true)));
|
||||||
val ? (column.hide = false) : (column.hide = true)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,11 +117,10 @@ const handleCheckAllChange = (val: boolean) => {
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
const handleCheckedColumnsChange = (value: string[]) => {
|
const handleCheckedColumnsChange = (value: string[]) => {
|
||||||
checkedColumns.value = value;
|
checkedColumns.value = value;
|
||||||
const checkedCount = value.length;
|
const checkedCount = value.length;
|
||||||
checkAll.value = checkedCount === checkColumnList.value.length;
|
checkAll.value = checkedCount === checkColumnList.value.length;
|
||||||
isIndeterminate.value =
|
isIndeterminate.value = checkedCount > 0 && checkedCount < checkColumnList.value.length;
|
||||||
checkedCount > 0 && checkedCount < checkColumnList.value.length;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,9 +128,7 @@ const handleCheckedColumnsChange = (value: string[]) => {
|
||||||
* @param label
|
* @param label
|
||||||
*/
|
*/
|
||||||
const handleCheckColumnListChange = (label: string) => {
|
const handleCheckColumnListChange = (label: string) => {
|
||||||
dynamicColumns.value.filter(item => item.label === label)[0].hide = !(
|
dynamicColumns.value.filter(item => item.label === label)[0].hide = !(event.target as any).checked;
|
||||||
event.target as any
|
|
||||||
).checked;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,72 +136,67 @@ const handleCheckColumnListChange = (label: string) => {
|
||||||
* @param label
|
* @param label
|
||||||
*/
|
*/
|
||||||
const isFixedColumn = (label: string) => {
|
const isFixedColumn = (label: string) => {
|
||||||
return dynamicColumns.value.filter(item => item.label === label)[0].fixed;
|
return dynamicColumns.value.filter(item => item.label === label)[0].fixed;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 重置自定义表格列字段
|
* * 重置自定义表格列字段
|
||||||
*/
|
*/
|
||||||
const onReset = async () => {
|
const onReset = async () => {
|
||||||
// 重置列表值
|
// 重置列表值
|
||||||
const list = [];
|
const list = [];
|
||||||
// 全选按钮设为true
|
// 全选按钮设为true
|
||||||
checkAll.value = true;
|
checkAll.value = true;
|
||||||
isIndeterminate.value = false;
|
isIndeterminate.value = false;
|
||||||
// 当前选中的列
|
// 当前选中的列
|
||||||
checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label");
|
checkedColumns.value = getKeyList(cloneDeep(filterColumns), 'label');
|
||||||
// ? 重新赋值,拖拽排序不会改变原有值,响应式数据的特性 直接对 ref 或 reactive 创建的变量进行赋值可能不会触发视图的更新
|
// ? 重新赋值,拖拽排序不会改变原有值,响应式数据的特性 直接对 ref 或 reactive 创建的变量进行赋值可能不会触发视图的更新
|
||||||
// ? Proxy 来追踪属性的访问和修改,使用异步方式确保正确更新视图
|
// ? Proxy 来追踪属性的访问和修改,使用异步方式确保正确更新视图
|
||||||
checkColumnList.value = [];
|
checkColumnList.value = [];
|
||||||
await nextTick(() => {
|
await nextTick(() => {
|
||||||
checkColumnList.value = getKeyList(filterColumns, "label");
|
checkColumnList.value = getKeyList(filterColumns, 'label');
|
||||||
});
|
});
|
||||||
|
|
||||||
// checkedColumns 是原有顺序,根据这个顺序重新得到list
|
// checkedColumns 是原有顺序,根据这个顺序重新得到list
|
||||||
checkedColumns.value.forEach(item => {
|
checkedColumns.value.forEach(item => {
|
||||||
dynamicColumns.value.forEach(column => {
|
dynamicColumns.value.forEach(column => {
|
||||||
if (column.label == item) {
|
if (column.label == item) {
|
||||||
list.push(column);
|
list.push(column);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
emit("changeColumn", list);
|
emit('changeColumn', list);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 列展示拖拽排序 */
|
/** 列展示拖拽排序 */
|
||||||
const rowDrop = (event: any) => {
|
const rowDrop = (event: any) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const wrapper: HTMLElement = (
|
const wrapper: HTMLElement = (instance?.proxy?.$refs[`GroupRef${unref(props.tableKey)}`] as any).$el.firstElementChild;
|
||||||
instance?.proxy?.$refs[`GroupRef${unref(props.tableKey)}`] as any
|
Sortable.create(wrapper, {
|
||||||
).$el.firstElementChild;
|
animation: 300,
|
||||||
Sortable.create(wrapper, {
|
handle: '.drag-btn',
|
||||||
animation: 300,
|
onEnd: ({ newIndex, oldIndex, item }) => {
|
||||||
handle: ".drag-btn",
|
const targetThElem = item;
|
||||||
onEnd: ({ newIndex, oldIndex, item }) => {
|
const wrapperElem = targetThElem.parentNode as HTMLElement;
|
||||||
const targetThElem = item;
|
const oldColumn = dynamicColumns.value[oldIndex];
|
||||||
const wrapperElem = targetThElem.parentNode as HTMLElement;
|
const newColumn = dynamicColumns.value[newIndex];
|
||||||
const oldColumn = dynamicColumns.value[oldIndex];
|
if (oldColumn?.fixed || newColumn?.fixed) {
|
||||||
const newColumn = dynamicColumns.value[newIndex];
|
// 当前列存在fixed属性 则不可拖拽
|
||||||
if (oldColumn?.fixed || newColumn?.fixed) {
|
const oldThElem = wrapperElem.children[oldIndex] as HTMLElement;
|
||||||
// 当前列存在fixed属性 则不可拖拽
|
if (newIndex > oldIndex) {
|
||||||
const oldThElem = wrapperElem.children[oldIndex] as HTMLElement;
|
wrapperElem.insertBefore(targetThElem, oldThElem);
|
||||||
if (newIndex > oldIndex) {
|
} else {
|
||||||
wrapperElem.insertBefore(targetThElem, oldThElem);
|
wrapperElem.insertBefore(targetThElem, oldThElem ? oldThElem.nextElementSibling : oldThElem);
|
||||||
} else {
|
}
|
||||||
wrapperElem.insertBefore(
|
return;
|
||||||
targetThElem,
|
}
|
||||||
oldThElem ? oldThElem.nextElementSibling : oldThElem
|
const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
|
||||||
);
|
dynamicColumns.value.splice(newIndex, 0, currentRow);
|
||||||
}
|
emit('changeColumn', dynamicColumns.value);
|
||||||
return;
|
},
|
||||||
}
|
});
|
||||||
const currentRow = dynamicColumns.value.splice(oldIndex, 1)[0];
|
}).then();
|
||||||
dynamicColumns.value.splice(newIndex, 0, currentRow);
|
|
||||||
emit("changeColumn", dynamicColumns.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).then();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,234 +204,153 @@ const rowDrop = (event: any) => {
|
||||||
* @param formEl
|
* @param formEl
|
||||||
*/
|
*/
|
||||||
const resetForm = (formEl: FormInstance | undefined) => {
|
const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.resetFields();
|
formEl.resetFields();
|
||||||
props.onSearch();
|
props.onSearch();
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
watch([() => props.column], () => {
|
watch([() => props.column], () => {
|
||||||
dynamicColumns.value = props.column;
|
dynamicColumns.value = props.column;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<!-- 表单设置,外加插槽 -->
|
<!-- 表单设置,外加插槽 -->
|
||||||
<el-form
|
<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">
|
||||||
v-show="tableQueryFormVisible"
|
<slot name="tableForm" />
|
||||||
ref="ruleFormRef"
|
<el-form-item>
|
||||||
:inline="true"
|
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch">
|
||||||
:model="model"
|
{{ $t('buttons.search') }}
|
||||||
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
|
</el-button>
|
||||||
@submit="onSearch"
|
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(ruleFormRef)">
|
||||||
>
|
{{ $t('buttons.rest') }}
|
||||||
<slot name="tableForm" />
|
</el-button>
|
||||||
<el-form-item>
|
</el-form-item>
|
||||||
<el-button
|
</el-form>
|
||||||
: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-form-item>
|
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<!-- 表格头部设置 -->
|
<!-- 表格头部设置 -->
|
||||||
<div class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
|
<div class="w-[99/100] mt-2 px-2 pb-2 bg-bg_color">
|
||||||
<div class="flex justify-between w-full h-[60px] p-4">
|
<div class="flex justify-between w-full h-[60px] p-4">
|
||||||
<!-- 自定义左边头部内容 -->
|
<!-- 自定义左边头部内容 -->
|
||||||
<slot name="tableTitle">
|
<slot name="tableTitle">
|
||||||
<p class="font-bold truncate">
|
<p class="font-bold truncate">
|
||||||
{{ tableTitle ? tableTitle : t(route.meta.title) }}
|
{{ tableTitle ? tableTitle : t(route.meta.title) }}
|
||||||
</p>
|
</p>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<!-- 自定义表格操作内容 -->
|
<!-- 自定义表格操作内容 -->
|
||||||
<slot name="tableOperation">
|
<slot name="tableOperation">
|
||||||
<div class="flex items-center justify-around">
|
<div class="flex items-center justify-around">
|
||||||
<!-- 插槽内容 -->
|
<!-- 插槽内容 -->
|
||||||
<div class="mr-4">
|
<div class="mr-4">
|
||||||
<slot name="tableButtons" />
|
<slot name="tableButtons" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 表格刷新按钮 -->
|
<!-- 表格刷新按钮 -->
|
||||||
<RefreshIcon
|
<RefreshIcon v-tippy="rendTipProps('刷新')" :class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`" @click="onReFresh" />
|
||||||
v-tippy="rendTipProps('刷新')"
|
<el-divider direction="vertical" />
|
||||||
:class="`w-[16px] ${iconClass()}} ${loading ? 'animate-spin' : ''}`"
|
|
||||||
@click="onReFresh"
|
|
||||||
/>
|
|
||||||
<el-divider direction="vertical" />
|
|
||||||
|
|
||||||
<!-- 选择表格大小 -->
|
<!-- 选择表格大小 -->
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<CollapseIcon :class="`w-[16px] ${iconClass()}`" />
|
<CollapseIcon :class="`w-[16px] ${iconClass()}`" />
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu class="translation">
|
<el-dropdown-menu class="translation">
|
||||||
<el-dropdown-item
|
<el-dropdown-item :style="getDropdownItemStyle(size, 'large')" @click="handleTableSizeClick('large')">
|
||||||
:style="getDropdownItemStyle(size, 'large')"
|
{{ $t('style.larger') }}
|
||||||
@click="handleTableSizeClick('large')"
|
</el-dropdown-item>
|
||||||
>
|
<el-dropdown-item :style="getDropdownItemStyle(size, 'default')" @click="handleTableSizeClick('default')">
|
||||||
{{ $t("style.larger") }}
|
{{ t('style.default') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
<el-dropdown-item :style="getDropdownItemStyle(size, 'small')" @click="handleTableSizeClick('small')">
|
||||||
:style="getDropdownItemStyle(size, 'default')"
|
{{ t('style.small') }}
|
||||||
@click="handleTableSizeClick('default')"
|
</el-dropdown-item>
|
||||||
>
|
</el-dropdown-menu>
|
||||||
{{ t("style.default") }}
|
</template>
|
||||||
</el-dropdown-item>
|
</el-dropdown>
|
||||||
<el-dropdown-item
|
<el-divider direction="vertical" />
|
||||||
:style="getDropdownItemStyle(size, 'small')"
|
|
||||||
@click="handleTableSizeClick('small')"
|
|
||||||
>
|
|
||||||
{{ t("style.small") }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
<el-divider direction="vertical" />
|
|
||||||
|
|
||||||
<!-- 表格列设置 -->
|
<!-- 表格列设置 -->
|
||||||
<el-popover
|
<el-popover :popper-style="{ padding: 0 }" placement="bottom-start" trigger="click" width="200">
|
||||||
:popper-style="{ padding: 0 }"
|
<template #reference>
|
||||||
placement="bottom-start"
|
<SettingIcon v-tippy="rendTipProps('列设置')" :class="`w-[16px] ${iconClass()}`" />
|
||||||
trigger="click"
|
</template>
|
||||||
width="200"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<SettingIcon
|
|
||||||
v-tippy="rendTipProps('列设置')"
|
|
||||||
:class="`w-[16px] ${iconClass()}`"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div :class="topClass()">
|
<div :class="topClass()">
|
||||||
<el-checkbox
|
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" class="!-mr-1" label="列展示" @change="handleCheckAllChange" />
|
||||||
v-model="checkAll"
|
<el-button link type="primary" @click="onReset">
|
||||||
:indeterminate="isIndeterminate"
|
{{ t('buttons.rest') }}
|
||||||
class="!-mr-1"
|
</el-button>
|
||||||
label="列展示"
|
</div>
|
||||||
@change="handleCheckAllChange"
|
|
||||||
/>
|
|
||||||
<el-button link type="primary" @click="onReset">
|
|
||||||
{{ t("buttons.rest") }}</el-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pt-[6px] pl-[11px]">
|
<div class="pt-[6px] pl-[11px]">
|
||||||
<el-scrollbar max-height="36vh">
|
<el-scrollbar max-height="36vh">
|
||||||
<el-checkbox-group
|
<el-checkbox-group :ref="`GroupRef${unref(props.tableKey)}`" :modelValue="checkedColumns" @change="handleCheckedColumnsChange">
|
||||||
:ref="`GroupRef${unref(props.tableKey)}`"
|
<el-space :alignment="'flex-start'" :size="0" direction="vertical">
|
||||||
:modelValue="checkedColumns"
|
<div v-for="(item, index) in checkColumnList" :key="index" class="flex items-center">
|
||||||
@change="handleCheckedColumnsChange"
|
<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)">
|
||||||
<el-space
|
<span :title="item" class="inline-block w-[120px] truncate hover:text-text_color_primary">
|
||||||
:alignment="'flex-start'"
|
{{ item }}
|
||||||
:size="0"
|
</span>
|
||||||
direction="vertical"
|
</el-checkbox>
|
||||||
>
|
</div>
|
||||||
<div
|
</el-space>
|
||||||
v-for="(item, index) in checkColumnList"
|
</el-checkbox-group>
|
||||||
:key="index"
|
</el-scrollbar>
|
||||||
class="flex items-center"
|
</div>
|
||||||
>
|
</el-popover>
|
||||||
<DragIcon
|
</div>
|
||||||
:class="`drag-btn w-[16px] mr-2 ${isFixedColumn(item) ? '!cursor-no-drop' : '!cursor-grab'}`"
|
</slot>
|
||||||
@mouseenter.prevent="rowDrop"
|
</div>
|
||||||
/>
|
<slot name="tableSelect" />
|
||||||
<el-checkbox
|
<pure-table
|
||||||
:key="index"
|
ref="tableRef"
|
||||||
:label="item"
|
:adaptiveConfig="{ offsetBottom: 108 }"
|
||||||
:value="item"
|
:columns="column"
|
||||||
@change="handleCheckColumnListChange(item)"
|
:data="dataList"
|
||||||
>
|
:header-cell-style="cellHeaderStyle"
|
||||||
<span
|
:loading="loading"
|
||||||
:title="item"
|
:pagination="pagination"
|
||||||
class="inline-block w-[120px] truncate hover:text-text_color_primary"
|
:paginationSmall="size === 'small'"
|
||||||
>
|
:size="size"
|
||||||
{{ item }}
|
adaptive
|
||||||
</span>
|
align-whole="center"
|
||||||
</el-checkbox>
|
border
|
||||||
</div>
|
row-key="id"
|
||||||
</el-space>
|
stripe
|
||||||
</el-checkbox-group>
|
table-layout="fixed"
|
||||||
</el-scrollbar>
|
v-bind="$attrs"
|
||||||
</div>
|
@page-size-change="handleSizeChange"
|
||||||
</el-popover>
|
@page-current-change="handleCurrentChange"
|
||||||
</div>
|
@selection-change="handleSelectionChange"
|
||||||
</slot>
|
>
|
||||||
</div>
|
<template v-for="item in column" :key="item.prop" v-slot:[item.slot]="scope" v-bind="item">
|
||||||
<slot name="tableSelect" />
|
<slot :name="item.slot" v-bind="scope" />
|
||||||
<pure-table
|
<slot v-if="item.slot === 'operation'" name="operation">
|
||||||
ref="tableRef"
|
<el-button :icon="EditPen" link type="warning" @click="tableEdit(scope)">修改 </el-button>
|
||||||
:adaptiveConfig="{ offsetBottom: 108 }"
|
<el-popconfirm :title="t('table.popConfirmTitle')" @confirm="tableDelete(scope)">
|
||||||
:columns="column"
|
<template #reference>
|
||||||
:data="dataList"
|
<el-button :icon="DeleteFilled" link type="danger">删除 </el-button>
|
||||||
:header-cell-style="cellHeaderStyle"
|
</template>
|
||||||
:loading="loading"
|
</el-popconfirm>
|
||||||
:pagination="pagination"
|
</slot>
|
||||||
:paginationSmall="size === 'small'"
|
</template>
|
||||||
:size="size"
|
</pure-table>
|
||||||
adaptive
|
</div>
|
||||||
align-whole="center"
|
</div>
|
||||||
border
|
|
||||||
row-key="id"
|
|
||||||
stripe
|
|
||||||
table-layout="fixed"
|
|
||||||
v-bind="$attrs"
|
|
||||||
@page-size-change="handleSizeChange"
|
|
||||||
@page-current-change="handleCurrentChange"
|
|
||||||
@selection-change="handleSelectionChange"
|
|
||||||
>
|
|
||||||
<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)"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<el-button :icon="DeleteFilled" link type="danger"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</el-popconfirm>
|
|
||||||
</slot>
|
|
||||||
</template>
|
|
||||||
</pure-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.el-dropdown-menu__item i) {
|
:deep(.el-dropdown-menu__item i) {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-form {
|
.search-form {
|
||||||
:deep(.el-form-item) {
|
:deep(.el-form-item) {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -169,19 +169,16 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const isFixedColumn = (label: string) => {
|
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) => {
|
const rendTippyProps = (content: string) => ({
|
||||||
// https://vue-tippy.netlify.app/props
|
content,
|
||||||
return {
|
offset: [0, 18],
|
||||||
content,
|
duration: [300, 0],
|
||||||
offset: [0, 18],
|
followCursor: true,
|
||||||
duration: [300, 0],
|
hideOnClick: 'toggle',
|
||||||
followCursor: true,
|
});
|
||||||
hideOnClick: 'toggle',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const reference = {
|
const reference = {
|
||||||
reference: () => <SettingIcon class={['w-[16px]', iconClass.value]} v-tippy={rendTippyProps('列设置')} />,
|
reference: () => <SettingIcon class={['w-[16px]', iconClass.value]} v-tippy={rendTippyProps('列设置')} />,
|
||||||
|
@ -198,9 +195,7 @@ export default defineComponent({
|
||||||
<>
|
<>
|
||||||
<ExpandIcon
|
<ExpandIcon
|
||||||
class={['w-[16px]', iconClass.value]}
|
class={['w-[16px]', iconClass.value]}
|
||||||
style={{
|
style={{ transform: isExpandAll.value ? 'none' : 'rotate(-90deg)' }}
|
||||||
transform: isExpandAll.value ? 'none' : 'rotate(-90deg)',
|
|
||||||
}}
|
|
||||||
v-tippy={rendTippyProps(isExpandAll.value ? '折叠' : '展开')}
|
v-tippy={rendTippyProps(isExpandAll.value ? '折叠' : '展开')}
|
||||||
onClick={() => onExpand()}
|
onClick={() => onExpand()}
|
||||||
/>
|
/>
|
||||||
|
@ -245,12 +240,7 @@ export default defineComponent({
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<el-divider direction='vertical' />
|
<el-divider direction='vertical' />
|
||||||
|
|
||||||
<iconifyIconOffline
|
<iconifyIconOffline class={['w-[16px]', iconClass.value]} icon={isFullscreen.value ? ExitFullscreen : Fullscreen} v-tippy={isFullscreen.value ? '退出全屏' : '全屏'} onClick={onFullscreen} />
|
||||||
class={['w-[16px]', iconClass.value]}
|
|
||||||
icon={isFullscreen.value ? ExitFullscreen : Fullscreen}
|
|
||||||
v-tippy={isFullscreen.value ? '退出全屏' : '全屏'}
|
|
||||||
onClick={() => onFullscreen()}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{slots.default({
|
{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 { 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', {
|
export const userI18nStore = defineStore('i18nStore', {
|
||||||
persist: true,
|
persist: true,
|
||||||
|
@ -8,6 +9,24 @@ export const userI18nStore = defineStore('i18nStore', {
|
||||||
return {
|
return {
|
||||||
// ? 多语言内容
|
// ? 多语言内容
|
||||||
i18n: {},
|
i18n: {},
|
||||||
|
// 多语言列表
|
||||||
|
i18nDataList: [],
|
||||||
|
// 多语言类型
|
||||||
|
i18nTypeList: [],
|
||||||
|
isAddShown: false,
|
||||||
|
// ? 分页查询结果
|
||||||
|
pagination: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 150,
|
||||||
|
total: 100,
|
||||||
|
pageSizes,
|
||||||
|
},
|
||||||
|
// 加载
|
||||||
|
loading: false,
|
||||||
|
// 添加弹窗
|
||||||
|
addDialogVisible: false,
|
||||||
|
// 更新弹窗
|
||||||
|
updateDialogVisible: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
|
@ -29,5 +48,36 @@ export const userI18nStore = defineStore('i18nStore', {
|
||||||
this.i18n = data;
|
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 type { VNode } from 'vue';
|
||||||
import { isFunction } from '@pureadmin/utils';
|
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';
|
import type { BaseResult } from '@/api/service/types';
|
||||||
|
|
||||||
type messageStyle = 'el' | 'antd';
|
type messageStyle = 'el' | 'antd';
|
||||||
|
@ -31,6 +31,15 @@ interface MessageParams {
|
||||||
onClose?: Function | null;
|
onClose?: Function | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 消息盒
|
||||||
|
interface MessageBox {
|
||||||
|
message: string | undefined;
|
||||||
|
title: string | undefined;
|
||||||
|
confirmMessage: any;
|
||||||
|
cancelMessage: any;
|
||||||
|
showMessage: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/** 用法非常简单,参考 src/views/components/message/index.vue 文件 */
|
/** 用法非常简单,参考 src/views/components/message/index.vue 文件 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,3 +100,34 @@ export const storeMessage = (result: BaseResult<any>) => {
|
||||||
message(result.message, { type: 'success' });
|
message(result.message, { type: 'success' });
|
||||||
return true;
|
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>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { FormInstance } from 'element-plus';
|
import { FormInstance } from 'element-plus';
|
||||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
import SimpleDialog from '@/components/BaseDialog/SimpleDialog.vue';
|
||||||
import SimpleDialog from '@/components/Dialog/SimpleDialog.vue';
|
|
||||||
import { userI18nStore } from '@/store/i18n/i18n';
|
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({
|
defineProps({
|
||||||
// 是否显示弹窗
|
// 是否显示弹窗
|
||||||
|
@ -33,7 +32,6 @@ defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const ruleFormRef = ref<FormInstance>();
|
const ruleFormRef = ref<FormInstance>();
|
||||||
const i18nTypeStore = useI18nTypeStore();
|
|
||||||
const i18nStore = userI18nStore();
|
const i18nStore = userI18nStore();
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
@ -44,15 +42,9 @@ defineExpose({
|
||||||
<template>
|
<template>
|
||||||
<SimpleDialog :show="visible" :title="title" width="600" @onCancel="onClose" @onConfirm="onSubmit(ruleFormRef)">
|
<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 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-form-item label="选择添加语言分类" prop="languageId">
|
||||||
<el-select v-model="form.languageId!" filterable placeholder="选择添加语言分类">
|
<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-select>
|
||||||
</el-form-item>
|
</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 { reactive } from 'vue';
|
||||||
import type { FormRules } from 'element-plus';
|
import type { FormRules } from 'element-plus';
|
||||||
import { $t } from '@/plugins/i18n';
|
|
||||||
|
|
||||||
export const columns: TableColumnList = [
|
export const columns: TableColumnList = [
|
||||||
{ type: 'selection' },
|
// { type: 'selection' },
|
||||||
{ type: 'index', label: $t('table.tableNumber'), width: 100 },
|
// { type: 'index', label: 'table.tableNumber', width: 100 },
|
||||||
{ label: $t('i18n.keyName'), prop: 'keyName' },
|
{ label: 'i18n.keyName', prop: 'keyName' },
|
||||||
{ label: $t('i18n.translate'), prop: 'translate' },
|
{ label: 'i18n.translate', prop: 'translate' },
|
||||||
{ label: $t('i18n.languageSummary'), prop: 'languageSummary' },
|
{ label: 'i18n.languageSummary', prop: 'languageSummary' },
|
||||||
{ label: $t('i18n.languageName'), prop: 'languageName' },
|
{ label: 'i18n.languageName', prop: 'languageName' },
|
||||||
{ label: $t('i18n.parentKeyName'), prop: 'parentKeyName' },
|
{ label: 'i18n.parentKeyName', prop: 'parentKeyName' },
|
||||||
{ label: $t('table.operation'), prop: 'operation', slot: 'operation' },
|
{ 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>
|
<script lang="ts" setup>
|
||||||
import SimpleDialog from '@/components/Dialog/SimpleDialog.vue';
|
import SimpleDialog from '@/components/BaseDialog/SimpleDialog.vue';
|
||||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { ElMessage, FormInstance } from 'element-plus';
|
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 { isDefaultOptions } from '@/enums/baseConstant';
|
||||||
|
import { $t } from '@/plugins/i18n';
|
||||||
|
import { userI18nStore } from '@/store/i18n/i18n';
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const i18nTypeStore = useI18nTypeStore();
|
const i18nStore = userI18nStore();
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
languageName: '',
|
languageName: '',
|
||||||
summary: '',
|
summary: '',
|
||||||
isDefalut: false,
|
isDefault: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,9 +23,9 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async valid => {
|
formEl.validate(async valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
await i18nTypeStore.addLanguageType(form);
|
await i18nStore.addI18nType(form);
|
||||||
await i18nTypeStore.getLanguageType();
|
await i18nStore.getI18nTypeList();
|
||||||
i18nTypeStore.isAddShown = false;
|
i18nStore.isAddShown = false;
|
||||||
} else {
|
} else {
|
||||||
ElMessage.warning('请填写必填项');
|
ElMessage.warning('请填写必填项');
|
||||||
}
|
}
|
||||||
|
@ -44,12 +45,12 @@ const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
* * 关闭弹窗
|
* * 关闭弹窗
|
||||||
*/
|
*/
|
||||||
const onCancel = (value: boolean) => {
|
const onCancel = (value: boolean) => {
|
||||||
i18nTypeStore.isAddShown = value;
|
i18nStore.isAddShown = value;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SimpleDialog :show="i18nTypeStore.isAddShown" width="600" @on-cancel="onCancel">
|
<SimpleDialog :show="i18nStore.isAddShown" width="600" @on-cancel="onCancel">
|
||||||
<template #header>
|
<template #header>
|
||||||
<h1>添加多语言种类</h1>
|
<h1>添加多语言种类</h1>
|
||||||
</template>
|
</template>
|
||||||
|
@ -62,7 +63,7 @@ const onCancel = (value: boolean) => {
|
||||||
<el-input v-model="form.summary" autocomplete="off" type="text" />
|
<el-input v-model="form.summary" autocomplete="off" type="text" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="是否为默认语言" prop="isDefault">
|
<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-option v-for="(item, index) in isDefaultOptions" :key="index" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</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 { ref } from 'vue';
|
||||||
import { delObjectProperty } from '@pureadmin/utils';
|
import { delObjectProperty } from '@pureadmin/utils';
|
||||||
import { $t } from '@/plugins/i18n';
|
|
||||||
import { useI18nTypeStore } from '@/store/i18n/i18nType';
|
|
||||||
import { isDefaultOptions } from '@/enums/baseConstant';
|
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 editMap = ref({});
|
||||||
|
|
||||||
export const columns: TableColumnList = [
|
export const columns: TableColumnList = [
|
||||||
{ type: 'index', label: '序号', width: 100 },
|
// { type: 'index', label: '序号', width: 100 },
|
||||||
{
|
{
|
||||||
label: $t('i18n.languageName'),
|
label: 'i18n.languageName',
|
||||||
prop: 'languageName',
|
prop: 'languageName',
|
||||||
cellRenderer({ row, index }) {
|
cellRenderer({ row, index }) {
|
||||||
return <>{editMap.value[index]?.editable ? <el-input v-model={row.languageName} /> : <p>{row.languageName}</p>}</>;
|
return <>{editMap.value[index]?.editable ? <el-input v-model={row.languageName} /> : <p>{row.languageName}</p>}</>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('i18n.languageSummary'),
|
label: 'i18n.languageSummary',
|
||||||
prop: 'summary',
|
prop: 'summary',
|
||||||
cellRenderer({ row, index }) {
|
cellRenderer({ row, index }) {
|
||||||
return <>{editMap.value[index]?.editable ? <el-input v-model={row.summary} /> : <p>{row.summary}</p>}</>;
|
return <>{editMap.value[index]?.editable ? <el-input v-model={row.summary} /> : <p>{row.summary}</p>}</>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: $t('i18n.isDefault'),
|
label: 'i18n.isDefault',
|
||||||
prop: 'isDefault',
|
prop: 'isDefault',
|
||||||
cellRenderer({ row, index }) {
|
cellRenderer({ row, index }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{editMap.value[index]?.editable ? (
|
{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 => (
|
{isDefaultOptions.map(item => (
|
||||||
<el-option key={item.value} label={item.label} value={item.value} />
|
<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
|
* @param index
|
||||||
*/
|
*/
|
||||||
export async function onSave(row: any, index: number) {
|
export async function onSave(row: any, index: number) {
|
||||||
await i18nTypeStore.updateLanguageType(row);
|
await i18nTypeStore.updateI18nType(row);
|
||||||
editMap.value[index].editable = false;
|
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) {
|
export function onCancel(index: number) {
|
||||||
editMap.value[index].editable = false;
|
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>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import ReCol from '@/components/MyCol';
|
import ReCol from '@/components/MyCol';
|
||||||
import { formRules } from './utils/rule';
|
import { formRules } from './utils/rule';
|
||||||
import { FormProps } from './utils/types';
|
import { FormProps } from './utils/types';
|
||||||
|
@ -8,6 +8,7 @@ import Segmented from '@/components/ReSegmented';
|
||||||
import ReAnimateSelector from '@/components/AnimateSelector';
|
import ReAnimateSelector from '@/components/AnimateSelector';
|
||||||
import { fixedTagOptions, frameLoadingOptions, hiddenTagOptions, keepAliveOptions, menuTypeOptions, showLinkOptions, showParentOptions } from '@/enums';
|
import { fixedTagOptions, frameLoadingOptions, hiddenTagOptions, keepAliveOptions, menuTypeOptions, showLinkOptions, showParentOptions } from '@/enums';
|
||||||
import { $t } from '@/plugins/i18n';
|
import { $t } from '@/plugins/i18n';
|
||||||
|
import { userMenuIconStore } from '@/store/modules/menuIcon';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<FormProps>(), {
|
const props = withDefaults(defineProps<FormProps>(), {
|
||||||
formInline: () => ({
|
formInline: () => ({
|
||||||
|
@ -33,9 +34,14 @@ const props = withDefaults(defineProps<FormProps>(), {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const menuIconStore = userMenuIconStore();
|
||||||
const ruleFormRef = ref();
|
const ruleFormRef = ref();
|
||||||
const newFormInline = ref(props.formInline);
|
const newFormInline = ref(props.formInline);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
menuIconStore.getMenuIconList();
|
||||||
|
});
|
||||||
|
|
||||||
defineExpose({ menuFormRef: ruleFormRef });
|
defineExpose({ menuFormRef: ruleFormRef });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { $t } from '@/plugins/i18n';
|
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 { useRenderIcon } from '@/components/ReIcon/src/hooks';
|
||||||
import Delete from '@iconify-icons/ep/delete';
|
import Delete from '@iconify-icons/ep/delete';
|
||||||
import EditPen from '@iconify-icons/ep/edit-pen';
|
import EditPen from '@iconify-icons/ep/edit-pen';
|
||||||
import Refresh from '@iconify-icons/ep/refresh';
|
import Refresh from '@iconify-icons/ep/refresh';
|
||||||
import AddFill from '@iconify-icons/ri/add-circle-line';
|
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 form from '@/views/role/form.vue';
|
||||||
import PureTable from '@pureadmin/table';
|
import PureTable from '@pureadmin/table';
|
||||||
import { columns } from '@/views/menu/utils/rule';
|
import { columns } from '@/views/menu/utils/rule';
|
||||||
|
@ -36,7 +36,7 @@ onMounted(() => {
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</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>
|
<template #buttons>
|
||||||
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="openDialog()"> 新增菜单</el-button>
|
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="openDialog()"> 新增菜单</el-button>
|
||||||
</template>
|
</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 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-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>
|
<template #reference>
|
||||||
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
|
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -34,14 +34,6 @@ export const getMenuType = (type, text = false) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 表格选择
|
|
||||||
* @param val
|
|
||||||
*/
|
|
||||||
export const handleSelectionChange = val => {
|
|
||||||
console.log('handleSelectionChange', val);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单重置
|
* 表单重置
|
||||||
* @param formEl
|
* @param formEl
|
||||||
|
@ -52,6 +44,10 @@ export const resetForm = async formEl => {
|
||||||
await onSearch();
|
await onSearch();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const handleSelectionChange = (val: any) => {
|
||||||
|
console.log('handleSelectionChange', val);
|
||||||
|
};
|
||||||
|
|
||||||
export const onSearch = async () => {
|
export const onSearch = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue