master
parent
c9d02287e4
commit
0e18fd3c33
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import Utils from '@/common/utils'
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
import Colls from '@/common/utils/colls.ts'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue?: string | string[] | null,
|
||||
multiple?: boolean,
|
||||
placeholder?: string,
|
||||
displayField: string,
|
||||
columns: {
|
||||
columns?: {
|
||||
label: string
|
||||
prop: string
|
||||
}[]
|
||||
|
|
@ -63,7 +64,10 @@ function onOpen() {
|
|||
paging()
|
||||
}
|
||||
|
||||
onMounted(onOpen)
|
||||
|
||||
function onClose() {
|
||||
searchForm.$reset()
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
|
|
@ -131,11 +135,13 @@ const displayData = computed(() => {
|
|||
if (props.multiple) {
|
||||
return `已选 ${selectRows.length} 条`
|
||||
}
|
||||
return tableDataList.value
|
||||
let data = tableDataList.value
|
||||
.filter(it => selectRows.includes(it.id))
|
||||
.map(it => ((it as Record<string, any>) [props.displayField] as any) ?? '')
|
||||
.join(' ')
|
||||
|
||||
if (Colls.isEmpty(data)) {
|
||||
data = selectRows as string[]
|
||||
}
|
||||
return data.join('')
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
@ -145,6 +151,9 @@ const displayData = computed(() => {
|
|||
placement="bottom"
|
||||
trigger="click"
|
||||
@visible-change="visibleChangeHandler">
|
||||
<template #default>
|
||||
<div>
|
||||
<slot :displayData="displayData" name="displayArea">
|
||||
<ElInput :model-value="displayData" :placeholder="placeholder" readonly>
|
||||
<template #suffix>
|
||||
<ElIcon class="clear-btn" @click.stop="onClear">
|
||||
|
|
@ -152,6 +161,9 @@ const displayData = computed(() => {
|
|||
</ElIcon>
|
||||
</template>
|
||||
</ElInput>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<template #dropdown>
|
||||
<div class="drop-table-content">
|
||||
<ElForm inline @submit.prevent="paging">
|
||||
|
|
@ -187,11 +199,13 @@ const displayData = computed(() => {
|
|||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="#" type="index"/>
|
||||
<slot name="columns">
|
||||
<ElTableColumn
|
||||
v-for="(item, i) in columns"
|
||||
:key="'a-drop-table-'+i"
|
||||
:label="item.label"
|
||||
:prop="item.prop"/>
|
||||
</slot>
|
||||
</ElTable>
|
||||
<ElDivider class="drop-table-content-divider"/>
|
||||
<ElPagination
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<script lang="ts" setup>
|
||||
import ADropTable from '@/components/a-drop-table/ADropTable.vue'
|
||||
import {
|
||||
type IconName,
|
||||
icons,
|
||||
} from '@/components/a-icon/iconfont.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.vue'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
|
||||
const model = defineModel<string | undefined | null>()
|
||||
const dropTableLoader = (param: { keywords: string } & G.PageParam) => {
|
||||
const dataList = icons.glyphs
|
||||
.filter(it => it.name.toLowerCase().includes(param.keywords.toLowerCase()) || it.font_class.toLowerCase().includes(param.keywords.toLowerCase()))
|
||||
.sort((a, b) => a.unicode_decimal - b.unicode_decimal)
|
||||
return Promise.resolve({
|
||||
current: param.current!,
|
||||
size: param.size,
|
||||
pages: Math.ceil(dataList.length / param.size!),
|
||||
total: dataList.length,
|
||||
records: dataList
|
||||
.filter((_, i) => {
|
||||
return i >= (param.current! - 1) * param.size! && i < param.current! * param.size!
|
||||
})
|
||||
.map(it => ({
|
||||
id: it.font_class,
|
||||
...it,
|
||||
})),
|
||||
} as G.PageResult)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ADropTable v-model="model"
|
||||
:loader="dropTableLoader"
|
||||
display-field="font_class">
|
||||
<template #displayArea="{displayData}">
|
||||
<div v-if=" Strings.isBlank(displayData)" class="display-area">请选择</div>
|
||||
<AIcon v-else :name="displayData as IconName" class="display-area"/>
|
||||
</template>
|
||||
<template #columns>
|
||||
<ElTableColumn label="图标" prop="font_class">
|
||||
<template #default="{row}">
|
||||
<AIcon :name="row.font_class as IconName"/>
|
||||
<span style="margin-left: 10px;display: inline-block">{{ row.font_class }}</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="名称" prop="name"/>
|
||||
</template>
|
||||
</ADropTable>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.display-area {
|
||||
cursor pointer
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* 项目名称 再昇云 */
|
||||
src: url('@/components/a-icon/iconfont.woff2?t=1771989909326') format('woff2'),
|
||||
url('@/components/a-icon/iconfont.woff?t=1771989909326') format('woff'),
|
||||
url('@/components/a-icon/iconfont.ttf?t=1771989909326') format('truetype');
|
||||
src: url('@/components/a-icon/iconfont.woff2?t=1772264126793') format('woff2'),
|
||||
url('@/components/a-icon/iconfont.woff?t=1772264126793') format('woff'),
|
||||
url('@/components/a-icon/iconfont.ttf?t=1772264126793') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
@ -13,6 +13,38 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-yulan:before {
|
||||
content: "\e668";
|
||||
}
|
||||
|
||||
.icon-putongzhihang:before {
|
||||
content: "\e663";
|
||||
}
|
||||
|
||||
.icon-zhihangjilu:before {
|
||||
content: "\e892";
|
||||
}
|
||||
|
||||
.icon-xitongguanli1:before {
|
||||
content: "\e6ae";
|
||||
}
|
||||
|
||||
.icon-API:before {
|
||||
content: "\e740";
|
||||
}
|
||||
|
||||
.icon-bianma:before {
|
||||
content: "\e772";
|
||||
}
|
||||
|
||||
.icon-caidan:before {
|
||||
content: "\e662";
|
||||
}
|
||||
|
||||
.icon-gongnengquanxian:before {
|
||||
content: "\e661";
|
||||
}
|
||||
|
||||
.icon-zhongzhimima:before {
|
||||
content: "\e660";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,62 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "7450656",
|
||||
"name": "预览",
|
||||
"font_class": "yulan",
|
||||
"unicode": "e668",
|
||||
"unicode_decimal": 58984
|
||||
},
|
||||
{
|
||||
"icon_id": "11493961",
|
||||
"name": "普通执行",
|
||||
"font_class": "putongzhihang",
|
||||
"unicode": "e663",
|
||||
"unicode_decimal": 58979
|
||||
},
|
||||
{
|
||||
"icon_id": "44782561",
|
||||
"name": "执行记录",
|
||||
"font_class": "zhihangjilu",
|
||||
"unicode": "e892",
|
||||
"unicode_decimal": 59538
|
||||
},
|
||||
{
|
||||
"icon_id": "12884221",
|
||||
"name": "系统管理",
|
||||
"font_class": "xitongguanli1",
|
||||
"unicode": "e6ae",
|
||||
"unicode_decimal": 59054
|
||||
},
|
||||
{
|
||||
"icon_id": "3351180",
|
||||
"name": "API",
|
||||
"font_class": "API",
|
||||
"unicode": "e740",
|
||||
"unicode_decimal": 59200
|
||||
},
|
||||
{
|
||||
"icon_id": "19105727",
|
||||
"name": "编码",
|
||||
"font_class": "bianma",
|
||||
"unicode": "e772",
|
||||
"unicode_decimal": 59250
|
||||
},
|
||||
{
|
||||
"icon_id": "7155218",
|
||||
"name": "菜单",
|
||||
"font_class": "caidan",
|
||||
"unicode": "e662",
|
||||
"unicode_decimal": 58978
|
||||
},
|
||||
{
|
||||
"icon_id": "12820163",
|
||||
"name": "功能权限",
|
||||
"font_class": "gongnengquanxian",
|
||||
"unicode": "e661",
|
||||
"unicode_decimal": 58977
|
||||
},
|
||||
{
|
||||
"icon_id": "524416",
|
||||
"name": "重置密码",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,62 @@ export const icons = {
|
|||
'css_prefix_text': 'icon-',
|
||||
'description': '',
|
||||
'glyphs': [
|
||||
{
|
||||
'icon_id': '7450656',
|
||||
'name': '预览',
|
||||
'font_class': 'yulan',
|
||||
'unicode': 'e668',
|
||||
'unicode_decimal': 58984,
|
||||
},
|
||||
{
|
||||
'icon_id': '11493961',
|
||||
'name': '普通执行',
|
||||
'font_class': 'putongzhihang',
|
||||
'unicode': 'e663',
|
||||
'unicode_decimal': 58979,
|
||||
},
|
||||
{
|
||||
'icon_id': '44782561',
|
||||
'name': '执行记录',
|
||||
'font_class': 'zhihangjilu',
|
||||
'unicode': 'e892',
|
||||
'unicode_decimal': 59538,
|
||||
},
|
||||
{
|
||||
'icon_id': '12884221',
|
||||
'name': '系统管理',
|
||||
'font_class': 'xitongguanli1',
|
||||
'unicode': 'e6ae',
|
||||
'unicode_decimal': 59054,
|
||||
},
|
||||
{
|
||||
'icon_id': '3351180',
|
||||
'name': 'API',
|
||||
'font_class': 'API',
|
||||
'unicode': 'e740',
|
||||
'unicode_decimal': 59200,
|
||||
},
|
||||
{
|
||||
'icon_id': '19105727',
|
||||
'name': '编码',
|
||||
'font_class': 'bianma',
|
||||
'unicode': 'e772',
|
||||
'unicode_decimal': 59250,
|
||||
},
|
||||
{
|
||||
'icon_id': '7155218',
|
||||
'name': '菜单',
|
||||
'font_class': 'caidan',
|
||||
'unicode': 'e662',
|
||||
'unicode_decimal': 58978,
|
||||
},
|
||||
{
|
||||
'icon_id': '12820163',
|
||||
'name': '功能权限',
|
||||
'font_class': 'gongnengquanxian',
|
||||
'unicode': 'e661',
|
||||
'unicode_decimal': 58977,
|
||||
},
|
||||
{
|
||||
'icon_id': '524416',
|
||||
'name': '重置密码',
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -102,6 +102,7 @@ interface FormPropsType<P, T extends DefaultRow> {
|
|||
* @param param 查询条件
|
||||
*/
|
||||
paging: (param: P) => Promise<R<G.PageResult<T>>>
|
||||
list?: (param: P) => Promise<R<T[]>>
|
||||
/**
|
||||
* 导出函数
|
||||
* @param param 查询条件
|
||||
|
|
@ -329,9 +330,19 @@ const component = defineComponent(
|
|||
loading.value = false
|
||||
})
|
||||
return
|
||||
} else if (props.searchForm.list != null) {
|
||||
props.searchForm.list(formData.$clone() as P)
|
||||
.then(res => {
|
||||
const records = res.data ?? ([] as T[])
|
||||
tableData.$reset(records)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
expose({doSearch})
|
||||
expose({doSearch, tableData})
|
||||
const showHighFormHandle = () => {
|
||||
showHighForm.value = !showHighForm.value
|
||||
formData.$reset()
|
||||
|
|
@ -634,7 +645,7 @@ const component = defineComponent(
|
|||
}
|
||||
</ElTable>, [ [ ElLoading.directive, loading.value ] ])
|
||||
}
|
||||
<ElPagination
|
||||
{props.searchForm.paging != null ? <ElPagination
|
||||
current-page={(formData as G.PageParam).current}
|
||||
page-size={(formData as G.PageParam).size}
|
||||
onUpdate:current-page={(val) => (formData as G.PageParam).current = val}
|
||||
|
|
@ -645,7 +656,7 @@ const component = defineComponent(
|
|||
total={totalCount.value}
|
||||
background={true}
|
||||
layout="total, prev, pager, next, sizes, jumper"
|
||||
onChange={doSearch}/>
|
||||
onChange={doSearch}/> : <></>}
|
||||
{
|
||||
slots?.default?.()
|
||||
}
|
||||
|
|
@ -658,8 +669,9 @@ const component = defineComponent(
|
|||
},
|
||||
)
|
||||
|
||||
export interface ATablePageInstance extends InstanceType<typeof component> {
|
||||
export interface ATablePageInstance<T extends DefaultRow = DefaultRow> extends InstanceType<typeof component> {
|
||||
doSearch: () => void
|
||||
tableData: T[]
|
||||
}
|
||||
|
||||
export default component
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ declare module 'vue' {
|
|||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElIconArrowRight: typeof import('@element-plus/icons-vue')['ArrowRight']
|
||||
ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
|
||||
ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
|
||||
ElIconPlus: typeof import('@element-plus/icons-vue')['Plus']
|
||||
|
|
@ -91,6 +92,7 @@ declare global {
|
|||
const ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
const ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
const ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
const ElIconArrowRight: typeof import('@element-plus/icons-vue')['ArrowRight']
|
||||
const ElIconCircleClose: typeof import('@element-plus/icons-vue')['CircleClose']
|
||||
const ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
|
||||
const ElIconPlus: typeof import('@element-plus/icons-vue')['Plus']
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<ElInput v-model="formData.categoryName" placeholder="分类名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序" prop="sort">
|
||||
<ElInputNumber v-model="formData.sort" :min="0" placeholder="排序"/>
|
||||
<ElInputNumber v-model="formData.sort" :min="0" controls-position="right" placeholder="排序"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注" prop="memo">
|
||||
<ElInput v-model="formData.memo" placeholder="备注"/>
|
||||
|
|
|
|||
|
|
@ -115,7 +115,6 @@ const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
|||
const uploaderIns = useTemplateRef<InstanceType<typeof Uploader>>('uploader')
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
const formPanelProps = buildFormPanelProps<GoodsTypes.GoodsForm>({
|
||||
// title: status.value === 'add' ? '新建产品' : '修改产品',
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{ searchForm }">
|
||||
<ElFormItem label="端点地址">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.endpointPath"
|
||||
v-model="formData.endpointPath"
|
||||
placeholder="端点地址"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
|
|
@ -18,28 +16,30 @@
|
|||
<ElTableColumn label="访问模式" prop="accessModelTxt"/>
|
||||
<ElTableColumn label="备注" prop="memo"/>
|
||||
</template>
|
||||
<EndpointForm ref="endpointForm" @edit-succ="research"/>
|
||||
</FormPage>
|
||||
<EndpointForm ref="endpointForm" :research="research"/>
|
||||
</ATablePage>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import EndpointApi from '@/pages/sys/endpoint/endpoint-api.ts'
|
||||
import EndpointForm from '@/pages/sys/endpoint/EndpointForm.vue'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildTablePageProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
const endpointFormIns = useTemplateRef<InstanceType<typeof EndpointForm>>('endpointForm')
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
const leftTools: ToolType[] = [
|
||||
const tablePageProps = buildTablePageProps<EndpointTypes.SearchEndpointParam, EndpointTypes.SearchEndpointResult>({
|
||||
pageLayout: {
|
||||
enableHighForm: false,
|
||||
},
|
||||
searchForm: {
|
||||
paging: EndpointApi.paging,
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
|
|
@ -47,8 +47,10 @@ const leftTools: ToolType[] = [
|
|||
endpointFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
const actionColumn = reactive<ActionColumnType<EndpointTypes.SearchEndpointResult>>({
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
|
|
@ -75,71 +77,14 @@ const actionColumn = reactive<ActionColumnType<EndpointTypes.SearchEndpointResul
|
|||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
function paging(param: EndpointTypes.SearchEndpointParam) {
|
||||
return EndpointApi.paging(param)
|
||||
function research() {
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.table-list {
|
||||
flex 1;
|
||||
margin 0 0 20px 0
|
||||
width 100%
|
||||
|
||||
:deep(.table-header) {
|
||||
color #454C59
|
||||
|
||||
th {
|
||||
background-color #EDF1F7
|
||||
font-weight 500
|
||||
position relative
|
||||
|
||||
& > div {
|
||||
display flex
|
||||
gap 5px
|
||||
align-items center
|
||||
}
|
||||
|
||||
&:not(:first-child) > div::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1px;
|
||||
width: 1px;
|
||||
background-color: #D3D7DE;
|
||||
transform: translateY(-50%);
|
||||
content: "";
|
||||
height 50%
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.table-cell) {
|
||||
color #2F3540
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width 100%
|
||||
display flex
|
||||
flex-wrap wrap
|
||||
|
||||
& > button {
|
||||
margin 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tool-bar {
|
||||
display flex
|
||||
justify-content space-between
|
||||
margin 0 0 20px 0
|
||||
}
|
||||
|
||||
.pagination {
|
||||
justify-content: end;
|
||||
margin: 8px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
<template>
|
||||
<ElDialog
|
||||
v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
width="fit-content"
|
||||
@close="dialogCloseHandler">
|
||||
<ElForm :model="formData"
|
||||
ref="endpointForm"
|
||||
:rules="rules"
|
||||
class="form-panel"
|
||||
>
|
||||
|
||||
<AFormPanel
|
||||
ref="formPanel"
|
||||
v-bind="formPanelProps">
|
||||
<template #default="formData">
|
||||
<div class="form-items">
|
||||
<ElFormItem label="请求方式" prop="requestMethod">
|
||||
<ElSelect
|
||||
v-model="formData.requestMethod"
|
||||
|
||||
placeholder="请求方式">
|
||||
<ElOption label="GET 请求" value="GET"/>
|
||||
<ElOption label="POST 请求" value="POST"/>
|
||||
|
|
@ -25,19 +17,16 @@
|
|||
<ElFormItem label="路由前缀" prop="routingPath">
|
||||
<ElInput
|
||||
v-model="formData.routingPath"
|
||||
|
||||
placeholder="以 / 开头 或 为空"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="端点地址" prop="endpointPath">
|
||||
<ElInput
|
||||
v-model="formData.endpointPath"
|
||||
|
||||
placeholder="以 / 开头"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="访问模式" prop="accessModel">
|
||||
<ElSelect
|
||||
v-model="formData.accessModel"
|
||||
|
||||
placeholder="访问模式">
|
||||
<ElOption label="允许匿名访问" value="Anonymous"/>
|
||||
<ElOption label="允许已登录用户访问" value="Logined"/>
|
||||
|
|
@ -48,37 +37,53 @@
|
|||
<ElFormItem label="备注" prop="memo">
|
||||
<ElInput
|
||||
v-model="formData.memo"
|
||||
|
||||
placeholder="备注"/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</AFormPanel>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import EndpointApi from '@/pages/sys/endpoint/endpoint-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import FormUtil from '@/common/utils/formUtil.ts'
|
||||
import {
|
||||
ElMessage,
|
||||
type FormInstance,
|
||||
type FormRules,
|
||||
} from 'element-plus'
|
||||
import type { InternalRuleItem } from 'async-validator/dist-types/interface'
|
||||
import AFormPanel, {
|
||||
type AFormPanelInstance,
|
||||
buildFormPanelProps,
|
||||
} from '@/components/a-form-panel/AFormPanel.tsx'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||
|
||||
const endpointFormIns = useTemplateRef<FormInstance>('endpointForm')
|
||||
|
||||
const formData = ref<EndpointTypes.SearchEndpointResult>({})
|
||||
const rules = reactive<FormRules<EndpointTypes.SearchEndpointResult>>({
|
||||
const props = withDefaults(defineProps<{
|
||||
research?: () => void
|
||||
}>(), {
|
||||
research: () => {
|
||||
},
|
||||
})
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
||||
const formPanelProps = buildFormPanelProps<GoodsTypes.GoodsForm>({
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
return Promise.resolve()
|
||||
} else {
|
||||
status.value = 'modify'
|
||||
return EndpointApi.detail(id!)
|
||||
.then((res) => {
|
||||
return res.data
|
||||
})
|
||||
}
|
||||
},
|
||||
doSubmit(data) {
|
||||
if (status.value === 'add') {
|
||||
return EndpointApi.add(data)
|
||||
.then(props.research)
|
||||
} else {
|
||||
return EndpointApi.modify(data)
|
||||
.then(props.research)
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
requestMethod: [ {required: true, message: '请选择请求方式', trigger: 'blur'} ],
|
||||
routingPath: [ {
|
||||
validator(_: InternalRuleItem, value: string, callback: (error?: string | Error) => void) {
|
||||
|
|
@ -107,57 +112,28 @@ const rules = reactive<FormRules<EndpointTypes.SearchEndpointResult>>({
|
|||
}, trigger: 'blur',
|
||||
} ],
|
||||
accessModel: [ {required: true, message: '请选择访问模式', trigger: 'blur'} ],
|
||||
},
|
||||
})
|
||||
|
||||
function dialogCloseHandler() {
|
||||
formData.value = {}
|
||||
}
|
||||
|
||||
function submitHandler() {
|
||||
if (status.value === 'view') return
|
||||
submiting.value = true
|
||||
if (formData.value.id != null) {
|
||||
FormUtil.submit(endpointFormIns, () => EndpointApi.modify(formData.value))
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
watchEffect(() => {
|
||||
formPanelProps.title = status.value === 'add' ? '新建产品' : '修改产品'
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
} else {
|
||||
FormUtil.submit(endpointFormIns, () => EndpointApi.add(formData.value))
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open(data: EndpointTypes.SearchEndpointResult = {}) {
|
||||
showDialog.value = true
|
||||
if (!Strings.isBlank(data.id)) {
|
||||
status.value = 'modify'
|
||||
EndpointApi.detail(data.id!)
|
||||
.then(res => {
|
||||
formData.value = res.data
|
||||
})
|
||||
} else {
|
||||
status.value = 'add'
|
||||
formData.value = data
|
||||
}
|
||||
open(data?: EndpointTypes.SearchEndpointResult) {
|
||||
formPanelIns.value?.open(data?.id)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.form-panel {
|
||||
padding 20px
|
||||
.form-items {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
&:last-child {
|
||||
grid-column: span 2;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
width="fit-content"
|
||||
@close="dialogCloseHandler"
|
||||
<ADialog v-model:show="showDialog"
|
||||
:closed="dialogCloseHandler"
|
||||
title="预览"
|
||||
>
|
||||
<div class="content">
|
||||
<ElForm :model="formData"
|
||||
|
|
@ -79,7 +77,7 @@
|
|||
<ElButton :loading="previewing" type="primary" @click="previewHandler">预览</ElButton>
|
||||
<ElButton :loading="downloading" type="primary" @click="downloadHandler">下载</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
|
|
@ -90,6 +88,7 @@ import {
|
|||
import TplApi from '@/pages/sys/gen/tpl/tpl-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import FormUtil from '@/common/utils/formUtil.ts'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const activeName = ref('')
|
||||
const showDialog = ref(false)
|
||||
|
|
@ -256,7 +255,7 @@ defineExpose({
|
|||
}
|
||||
|
||||
& > div:nth-child(3) {
|
||||
width: calc(800px - 272px);
|
||||
width: calc(800px - 288px);
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<FormPage
|
||||
:action-column="actionColumn"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{searchForm}">
|
||||
<ElFormItem label="表名称">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.tableName"
|
||||
v-model="formData.tableName"
|
||||
placeholder="表名称"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
|
|
@ -15,30 +15,35 @@
|
|||
<ElTableColumn label="备注" prop="tableComment"/>
|
||||
</template>
|
||||
<CodePreview ref="codePreview"/>
|
||||
</FormPage>
|
||||
</ATablePage>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import CodePreview from '@/pages/sys/gen/db-table/CodePreview.vue'
|
||||
import DbTableApi from '@/pages/sys/gen/db-table/db-table-api.ts'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type { ActionColumnType } from '@/components/page/a-page-type.ts'
|
||||
import ATablePage, { buildTablePageProps } from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const codePreviewIns = useTemplateRef<InstanceType<typeof CodePreview>>('codePreview')
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<DbTableTypes.TableInfo>>({
|
||||
const tablePageProps = buildTablePageProps<DbTableTypes.SearchTplParam, DbTableTypes.TableInfo>({
|
||||
pageLayout: {
|
||||
enableHighForm: false,
|
||||
},
|
||||
searchForm: {
|
||||
paging: DbTableApi.tablePaing,
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '预览',
|
||||
icon: 'Edit',
|
||||
icon: 'yulan',
|
||||
action({row}: { row: DbTableTypes.TableInfo }) {
|
||||
codePreviewIns.value?.open(row)
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
function paging(param: DbTableTypes.SearchTplParam) {
|
||||
return DbTableApi.tablePaing(param)
|
||||
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,16 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:default-search-form="defaultSearchForm"
|
||||
:left-tools="leftTools"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{searchForm}">
|
||||
<ElFormItem label="模板名称">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.tplName"
|
||||
v-model="formData.tplName"
|
||||
placeholder="模板名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="前端/后端">
|
||||
<ElFormItem>
|
||||
<ElSelect
|
||||
v-model="searchForm.lang"
|
||||
v-model="formData.lang"
|
||||
placeholder="前端/后端"
|
||||
>
|
||||
<ElOption
|
||||
|
|
@ -40,27 +37,38 @@
|
|||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
<TplForm ref="tplForm" @edit-succ="research"/>
|
||||
</FormPage>
|
||||
<TplForm ref="tplForm" :research="research"/>
|
||||
</ATablePage>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TplApi from '@/pages/sys/gen/tpl/tpl-api.ts'
|
||||
import TplForm from '@/pages/sys/gen/tpl/TplForm.vue'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildTablePageProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const defaultSearchForm: TplTypes.SearchTplParam = {
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
const tplFormIns = useTemplateRef<InstanceType<typeof TplForm>>('tplForm')
|
||||
const tablePageProps = buildTablePageProps<TplTypes.SearchTplParam, TplTypes.SearchTplResult>({
|
||||
pageLayout: {
|
||||
enableHighForm: false,
|
||||
},
|
||||
searchForm: {
|
||||
defaultData: {
|
||||
orders: 'lang,tpl_name',
|
||||
tpl: {},
|
||||
}
|
||||
const tplFormIns = useTemplateRef<InstanceType<typeof TplForm>>('tplForm')
|
||||
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
const leftTools: ToolType[] = [
|
||||
},
|
||||
highForm: {
|
||||
contentWidth: 320,
|
||||
},
|
||||
simpleForm: {
|
||||
colCount: 2,
|
||||
},
|
||||
paging: TplApi.paging,
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
|
|
@ -68,8 +76,10 @@ const leftTools: ToolType[] = [
|
|||
tplFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
const actionColumn = reactive<ActionColumnType<TplTypes.SearchTplResult>>({
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
|
|
@ -96,13 +106,12 @@ const actionColumn = reactive<ActionColumnType<TplTypes.SearchTplResult>>({
|
|||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function paging(param: TplTypes.SearchTplParam) {
|
||||
return TplApi.paging(param)
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
<ADialog v-model:show="showDialog"
|
||||
:title="status==='add'?'新增模板':'修改模板'"
|
||||
width="25vw"
|
||||
@close="dialogCloseHandler">
|
||||
<ElForm :model="tplFormData"
|
||||
|
|
@ -10,13 +9,11 @@
|
|||
<ElFormItem label="模板名称">
|
||||
<ElInput
|
||||
v-model="tplFormData.tplName"
|
||||
|
||||
placeholder="模板名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="前端/后端">
|
||||
<ElSelect
|
||||
v-model="tplFormData.lang"
|
||||
|
||||
placeholder="前端/后端"
|
||||
>
|
||||
<ElOption
|
||||
|
|
@ -31,7 +28,6 @@
|
|||
<ElInput
|
||||
v-model="tplFormData.tpl.content"
|
||||
:spellcheck="false"
|
||||
|
||||
placeholder="模板内容"
|
||||
resize="none"
|
||||
type="textarea"/>
|
||||
|
|
@ -41,7 +37,6 @@
|
|||
<ElInput
|
||||
:spellcheck="false"
|
||||
v-model="tplFormData.tpl.dir"
|
||||
|
||||
placeholder="文件路径"
|
||||
resize="none"
|
||||
type="textarea"/>
|
||||
|
|
@ -51,7 +46,6 @@
|
|||
<ElInput
|
||||
:spellcheck="false"
|
||||
v-model="tplFormData.tpl.filename"
|
||||
|
||||
placeholder="文件名称"
|
||||
resize="none"
|
||||
type="textarea"/>
|
||||
|
|
@ -61,12 +55,13 @@
|
|||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TplApi from '@/pages/sys/gen/tpl/tpl-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
const showDialog = ref(false)
|
||||
|
|
|
|||
|
|
@ -1,80 +1,48 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close width="25vw" @close="dialogCloseHandler">
|
||||
<ElForm :model="menuForm" class="menu-form">
|
||||
<AFormPanel
|
||||
ref="formPanel"
|
||||
v-bind="formPanelProps">
|
||||
<template #default="formData">
|
||||
<div class="form-items">
|
||||
<ElFormItem label="上级">
|
||||
<ElTreeSelect v-model="menuForm.pid" :data="menuTreeDataSource" :default-expanded-keys="['0']" :render-after-expand="false" check-strictly placeholder="选择上级菜单"/>
|
||||
<ElTreeSelect v-model="formData.pid" v-loading="loadingMenus" :data="menuTreeDataSource" :default-expanded-keys="['0']" :render-after-expand="false" check-strictly placeholder="选择上级菜单"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="客户端" prop="clients">
|
||||
<ElCheckboxGroup v-model="menuForm.clients">
|
||||
<ElCheckboxGroup v-model="formData.clients">
|
||||
<ElCheckbox v-for="client in ClientUtil.clients" :key="client.val" :label="client.txt" :value="client.val"/>
|
||||
</ElCheckboxGroup>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="类型">
|
||||
<ElSelect v-model="menuForm.menuCategory" :data="menuCategoryData" placeholder="选择类型">
|
||||
<ElSelect v-model="formData.menuCategory" :data="menuCategoryData" placeholder="选择类型">
|
||||
<ElOption v-for="menuCategory in menuCategoryData" :key="menuCategory.key" :label="menuCategory.label" :value="menuCategory.key"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="名称">
|
||||
<ElInput v-model="menuForm.title" placeholder="名称"/>
|
||||
<ElInput v-model="formData.title" placeholder="名称"/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="menuForm.menuCategory === MenuCategory.Page || menuForm.menuCategory === MenuCategory.SubPage" label="路由名称">
|
||||
<ElInput v-model="menuForm.routeName" :min="0" placeholder="路由名称"/>
|
||||
<ElFormItem v-if="formData.menuCategory === MenuCategory.Page || formData.menuCategory === MenuCategory.SubPage" label="路由名称">
|
||||
<ElInput v-model="formData.routeName" :min="0" placeholder="路由名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="menuForm.menuCategory === MenuCategory.Page || menuForm.menuCategory === MenuCategory.SubPage" label="路由地址">
|
||||
<ElInput v-model="menuForm.routePath" :min="0" placeholder="路由地址"/>
|
||||
<ElFormItem v-if="formData.menuCategory === MenuCategory.Page || formData.menuCategory === MenuCategory.SubPage" label="路由地址">
|
||||
<ElInput v-model="formData.routePath" :min="0" placeholder="路由地址"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="编码">
|
||||
<ElInput v-model="menuForm.sn" :min="0" placeholder="编码"/>
|
||||
<ElInput v-model="formData.sn" :min="0" placeholder="编码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="图标">
|
||||
<ElDropdown closable header="图标列表" placement="bottom" style="width: 100%" trigger="click">
|
||||
<ElInput v-model="menuForm.iconName" placeholder="选择图标" readonly>
|
||||
<template #suffix>
|
||||
<AIcon :name="menuForm.icon!"/>
|
||||
</template>
|
||||
</ElInput>
|
||||
<template #dropdown>
|
||||
<div class="dropdown-table-wrapper">
|
||||
<ElTable
|
||||
ref="dropdownTable"
|
||||
:data="iconTableDataSource"
|
||||
cell-class-name="table-cell"
|
||||
class="table-list"
|
||||
empty-text="暂无数据"
|
||||
header-row-class-name="table-header"
|
||||
row-key="id"
|
||||
width="324"
|
||||
@current-change="currentChangeHandler">
|
||||
<ElTableColumn label="#" type="index"/>
|
||||
<ElTableColumn label="图标" prop="font_class">
|
||||
<template #default="scope">
|
||||
<AIcon :name="scope?.row?.font_class"/>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="名称" prop="name"/>
|
||||
</ElTable>
|
||||
<ElPagination :page-size="pagination.size" :total="pagination.total" layout="total, prev, pager, next" @change="pageChangeHandler"/>
|
||||
</div>
|
||||
</template>
|
||||
</ElDropdown>
|
||||
<AIconDropTable v-model="formData.icon"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="排序">
|
||||
<ElInputNumber v-model="menuForm.sort" :min="0" placeholder="排序" style="width: 100%"/>
|
||||
<ElInputNumber v-model="formData.sort" :min="0" controls-position="right" placeholder="排序"/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</AFormPanel>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
MenuCategory,
|
||||
MenuCategoryDict,
|
||||
|
|
@ -82,62 +50,23 @@ import {
|
|||
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
||||
import Colls from '@/common/utils/colls.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import {
|
||||
ElMessage,
|
||||
type TableInstance,
|
||||
} from 'element-plus'
|
||||
import {
|
||||
type IconGlyphs,
|
||||
icons,
|
||||
} from '@/components/a-icon/iconfont.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.vue'
|
||||
import ClientUtil from '@/common/utils/client-util.ts'
|
||||
import Utils from '@/common/utils'
|
||||
import AFormPanel, {
|
||||
type AFormPanelInstance,
|
||||
buildFormPanelProps,
|
||||
} from '@/components/a-form-panel/AFormPanel.tsx'
|
||||
import AIconDropTable from '@/components/a-icon/AIconDropTable.vue'
|
||||
import { nanoid } from 'nanoid'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
|
||||
const pagination = reactive<G.Pagination>({
|
||||
total: icons.glyphs.length,
|
||||
pages: Math.ceil(icons.glyphs.length / 5),
|
||||
current: 1,
|
||||
size: 5,
|
||||
const props = withDefaults(defineProps<{
|
||||
research?: () => void
|
||||
}>(), {
|
||||
research: () => {
|
||||
},
|
||||
})
|
||||
|
||||
function dialogCloseHandler() {
|
||||
menuForm.value = {
|
||||
icon: 'dianzixiaopiao',
|
||||
}
|
||||
}
|
||||
|
||||
function pageChangeHandler(currentPage: number, pageSize: number) {
|
||||
pagination.current = currentPage
|
||||
pagination.size = pageSize
|
||||
iconTableDataSource.value = icons.glyphs.filter((_, i) => {
|
||||
return i >= (currentPage - 1) * pageSize && i < currentPage * pageSize
|
||||
})
|
||||
}
|
||||
|
||||
const dropdownTableIns = useTemplateRef<TableInstance>('dropdownTable')
|
||||
|
||||
let menuForm = ref<MenuTypes.MenuForm>({
|
||||
icon: 'dianzixiaopiao',
|
||||
})
|
||||
|
||||
const iconTableDataSource = ref<IconGlyphs[]>(
|
||||
icons.glyphs.filter((_, i) => {
|
||||
return i >= 0 && i < 5
|
||||
}),
|
||||
)
|
||||
|
||||
function currentChangeHandler(val?: IconGlyphs) {
|
||||
if (val == null) return
|
||||
menuForm.value.icon = val.font_class
|
||||
menuForm.value.iconName = val.name
|
||||
}
|
||||
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
const loadingMenus = ref<boolean>(false)
|
||||
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
||||
|
||||
const menuCategoryData = computed(() => {
|
||||
const data: { key: string; label: string }[] = []
|
||||
|
|
@ -151,66 +80,61 @@ const menuCategoryData = computed(() => {
|
|||
})
|
||||
|
||||
const menuTreeDataSource = ref<MenuTypes.SysMenu[]>()
|
||||
|
||||
|
||||
function submitHandler() {
|
||||
if (status.value === 'view') return
|
||||
submiting.value = true
|
||||
|
||||
menuForm.value.clientCode = ClientUtil.getClientCode(menuForm.value.clients!)
|
||||
if (menuForm.value.id != null) {
|
||||
MenuApi.modify(menuForm.value)
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
showDialog.value = false
|
||||
emits(('editSucc'))
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
} else {
|
||||
MenuApi.add(menuForm.value)
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
showDialog.value = false
|
||||
emits(('editSucc'))
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open(data: MenuTypes.MenuForm = {
|
||||
const formPanelProps = buildFormPanelProps<MenuTypes.MenuForm>({
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
return Promise.resolve({
|
||||
icon: 'dianzixiaopiao',
|
||||
}) {
|
||||
if (!Strings.isBlank(data.id)) {
|
||||
pid: '0',
|
||||
clients: [ 1 ],
|
||||
menuCategory: MenuCategory.Catalog,
|
||||
sn: nanoid(10),
|
||||
} as MenuTypes.MenuForm)
|
||||
} else {
|
||||
status.value = 'modify'
|
||||
data = Utils.clone(data)
|
||||
data.clients = ClientUtil.getClients(data.clientCode!).map(it => it.val)
|
||||
menuForm.value = data
|
||||
return MenuApi
|
||||
.detail(id!)
|
||||
.then((res) => {
|
||||
return {
|
||||
...res.data,
|
||||
clients: ClientUtil.getClients(res.data.clientCode!).map(it => it.val),
|
||||
} as MenuTypes.MenuForm
|
||||
})
|
||||
}
|
||||
},
|
||||
doSubmit(data) {
|
||||
if (status.value === 'add') {
|
||||
return MenuApi.add(data)
|
||||
.then(props.research)
|
||||
} else {
|
||||
menuForm.value = {
|
||||
icon: 'dianzixiaopiao',
|
||||
return MenuApi.modify(data)
|
||||
.then(props.research)
|
||||
}
|
||||
}
|
||||
showDialog.value = true
|
||||
dropdownTableIns.value?.setCurrentRow(icons.glyphs.find((it) => it.font_class === data.icon))
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
MenuApi.list().then(({data}) => {
|
||||
watchEffect(() => {
|
||||
formPanelProps.title = status.value === 'add' ? '新建菜单' : '修改菜单'
|
||||
})
|
||||
defineExpose({
|
||||
open(data?: MenuTypes.MenuForm) {
|
||||
loadingMenus.value = true
|
||||
MenuApi.list()
|
||||
.then(({data}) => {
|
||||
const nodes = Colls.toTree(data.map((it) => ({value: it.id, label: it.title, ...it})))
|
||||
menuTreeDataSource.value = [ {value: '0', label: '顶级菜单', id: '0', pid: '0', children: nodes} ]
|
||||
})
|
||||
.finally(() => {
|
||||
loadingMenus.value = false
|
||||
})
|
||||
formPanelIns.value?.open(data?.id)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.menu-form {
|
||||
padding 20px
|
||||
.form-items {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.dropdown-table-wrapper {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,13 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:list="listAll"
|
||||
:table-props="{
|
||||
treeProps: { children: 'children', hasChildren: 'hasChildren' },
|
||||
treeLoad: treeLoad,
|
||||
}"
|
||||
>
|
||||
<template #searchFormItem="{ searchForm }">
|
||||
<ElFormItem label="菜单名称">
|
||||
<ElInput v-model="searchForm.title" placeholder="菜单名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="路由名称">
|
||||
<ElInput v-model="searchForm.routeName" placeholder="路由名称"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #simpleSearchFormItem="{ searchForm }">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput v-model="searchForm.title" placeholder="菜单名称"/>
|
||||
<ElInput v-model="formData.title" placeholder="菜单名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElInput v-model="searchForm.routeName" placeholder="路由名称"/>
|
||||
<ElInput v-model="formData.routeName" placeholder="路由名称"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
|
|
@ -48,12 +33,9 @@
|
|||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
</template>
|
||||
|
||||
<MenuForm ref="menuForm" @editSucc="research"/>
|
||||
|
||||
</FormPage>
|
||||
<MenuForm ref="menuForm" :research="research"/>
|
||||
</ATablePage>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
@ -61,17 +43,50 @@ import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
|||
import MenuForm from '@/pages/sys/menus/MenuForm.vue'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.vue'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildTablePageProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
import Colls from '@/common/utils/colls.ts'
|
||||
|
||||
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<MenuTypes.SysMenu>>({
|
||||
const tablePageProps = buildTablePageProps<MenuTypes.SearchForm, MenuTypes.SysMenu>({
|
||||
pageLayout: {
|
||||
enableHighForm: false,
|
||||
},
|
||||
searchForm: {
|
||||
simpleForm: {
|
||||
colCount: 2,
|
||||
},
|
||||
list() {
|
||||
return MenuApi.listAll()
|
||||
.then(res => {
|
||||
res.data = Colls.toTree(res.data ?? [])
|
||||
.map(it => {
|
||||
return {
|
||||
...it,
|
||||
hasChildren: !Colls.isEmpty(it.children),
|
||||
}
|
||||
})
|
||||
return res
|
||||
})
|
||||
},
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
menuFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
|
|
@ -98,52 +113,24 @@ const actionColumn = reactive<ActionColumnType<MenuTypes.SysMenu>>({
|
|||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
const leftTools: ToolType[] = [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
menuFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function listAll(param: MenuTypes.SearchForm) {
|
||||
return MenuApi.listAll({...param, pid: '0'})
|
||||
.then(res => {
|
||||
const data = res.data ?? []
|
||||
for (let it of data) {
|
||||
it.hasChildren = true
|
||||
it.children = []
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function treeLoad(param: MenuTypes.SearchForm, row: MenuTypes.SysMenu, expanded: any, resolve?: (data: MenuTypes.SysMenu[]) => void) {
|
||||
if (resolve == null && !expanded) return
|
||||
MenuApi.listAll({...param, pid: row.id})
|
||||
.then(res => {
|
||||
if (resolve != null) {
|
||||
resolve(res.data?.map(it => {
|
||||
it.hasChildren = true
|
||||
return it
|
||||
}) ?? [])
|
||||
} else {
|
||||
formPageIns.value?.dataTableIns?.updateKeyChildren(row.id, res.data?.map(it => {
|
||||
it.hasChildren = true
|
||||
it.children = []
|
||||
return it
|
||||
}) ?? [])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.expand-btn {
|
||||
margin-right 5px
|
||||
cursor pointer
|
||||
transition transform .3s ease-in-out
|
||||
margin-left calc(var(--expand-indent) * 16px)
|
||||
|
||||
&.expand-btn-expanded {
|
||||
transform rotateZ(90deg)
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export default {
|
|||
return get<G.PageResult<MenuTypes.SysMenu>>('/menu/page_list', data)
|
||||
},
|
||||
paging(data: MenuTypes.SearchForm & G.PageParam) {
|
||||
return get<G.PageResult<MenuTypes.SysMenu>>('/menu/page_list', data)
|
||||
return get<G.PageResult<MenuTypes.SysMenu>>('/menu/paging', data)
|
||||
},
|
||||
list(data?: MenuTypes.SearchForm | null) {
|
||||
return get<MenuTypes.SysMenu[]>('/menu/list_all', data)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ declare global {
|
|||
// 面包路径
|
||||
breadcrumb?: string[]
|
||||
menuCategory?: MenuCategory
|
||||
hasChildren?: boolean
|
||||
children?: SysMenu[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
<ADialog v-model:show="showDialog"
|
||||
title="分配资源"
|
||||
width="900">
|
||||
<ElTransfer
|
||||
v-model="rightValue"
|
||||
|
|
@ -53,7 +52,7 @@
|
|||
<ElButton @click="showDialog = false">取消</ElButton>
|
||||
<ElButton :disabled="rightValue.length <= 0" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleApi from '@/pages/sys/role/role-api.ts'
|
||||
|
|
@ -63,6 +62,7 @@ import {
|
|||
type TransferDataItem,
|
||||
} from 'element-plus'
|
||||
import ResourceApi from '@/pages/sys/resource/resource-api.ts'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
|
|
|
|||
|
|
@ -1,60 +1,64 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{ searchForm }">
|
||||
<ElFormItem label="角色代码">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.roleCode"
|
||||
v-model="formData.roleCode"
|
||||
placeholder="角色代码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="角色名称">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.roleName"
|
||||
v-model="formData.roleName"
|
||||
placeholder="角色名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注">
|
||||
<ElInput
|
||||
v-model="searchForm.memo"
|
||||
placeholder="备注"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
<ElTableColumn label="角色代码" prop="roleCode"/>
|
||||
<ElTableColumn label="角色名称" prop="roleName"/>
|
||||
<ElTableColumn label="备注" prop="memo"/>
|
||||
</template>
|
||||
<RoleForm ref="roleForm" @edit-succ="research"/>
|
||||
<RoleForm ref="roleForm" :research="research"/>
|
||||
<BindRes ref="bindRes"/>
|
||||
</FormPage>
|
||||
</ATablePage>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleApi from '@/pages/sys/role/role-api.ts'
|
||||
import RoleForm from '@/pages/sys/role/RoleForm.vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import BindRes from '@/pages/sys/role/BindRes.vue'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildTablePageProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const roleFormIns = useTemplateRef<InstanceType<typeof RoleForm>>('roleForm')
|
||||
const bindResIns = useTemplateRef<InstanceType<typeof BindRes>>('bindRes')
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<RoleTypes.SearchRoleResult>>({
|
||||
tableActions: [
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
const tablePageProps = buildTablePageProps<RoleTypes.SearchRoleParam, RoleTypes.SearchRoleResult>({
|
||||
pageLayout: {
|
||||
enableHighForm: false,
|
||||
},
|
||||
searchForm: {
|
||||
simpleForm: {colCount: 2},
|
||||
paging: RoleApi.paging,
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
tooltip: '资源',
|
||||
icon: 'ScaleToOriginal',
|
||||
action({row}: { row: RoleTypes.SearchRoleResult }) {
|
||||
bindResIns.value?.open(row.id!)
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
roleFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
|
||||
{
|
||||
tooltip: '编辑',
|
||||
icon: 'Edit',
|
||||
|
|
@ -70,11 +74,22 @@ const actionColumn = reactive<ActionColumnType<RoleTypes.SearchRoleResult>>({
|
|||
roleFormIns.value?.open(row)
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: '资源',
|
||||
type: 'warning',
|
||||
icon: 'caidan',
|
||||
action({row}: { row: RoleTypes.SearchRoleResult }) {
|
||||
bindResIns.value?.open(row.id!)
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'Delete',
|
||||
loading: false,
|
||||
type: 'danger',
|
||||
tooltip: '删除',
|
||||
show({row}) {
|
||||
return row.id != '1'
|
||||
},
|
||||
confirm: {
|
||||
title: '是否删除当前数据',
|
||||
},
|
||||
|
|
@ -91,22 +106,11 @@ const actionColumn = reactive<ActionColumnType<RoleTypes.SearchRoleResult>>({
|
|||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
const leftTools: ToolType[] = [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
roleFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function paging(params: RoleTypes.SearchRoleParam) {
|
||||
return RoleApi.paging(params)
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,91 +1,77 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
@close="dialogCloseHandler"
|
||||
destroy-on-close
|
||||
width="25vw">
|
||||
<ElForm :model="roleFormData"
|
||||
class="sys_role-form"
|
||||
>
|
||||
<AFormPanel
|
||||
ref="formPanel"
|
||||
v-bind="formPanelProps">
|
||||
<template #default="formData">
|
||||
<div class="form-items">
|
||||
<ElFormItem label="角色代码">
|
||||
<ElInput
|
||||
v-model="roleFormData.roleCode"
|
||||
|
||||
v-model="formData.roleCode"
|
||||
placeholder="角色代码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="角色名称">
|
||||
<ElInput
|
||||
v-model="roleFormData.roleName"
|
||||
|
||||
v-model="formData.roleName"
|
||||
placeholder="角色名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注">
|
||||
<ElInput
|
||||
v-model="roleFormData.memo"
|
||||
|
||||
v-model="formData.memo"
|
||||
placeholder="备注"/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</AFormPanel>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleApi from '@/pages/sys/role/role-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import AFormPanel, {
|
||||
type AFormPanelInstance,
|
||||
buildFormPanelProps,
|
||||
} from '@/components/a-form-panel/AFormPanel.tsx'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||
const roleFormData = ref<RoleTypes.SearchRoleResult>({})
|
||||
|
||||
function dialogCloseHandler() {
|
||||
roleFormData.value = {}
|
||||
}
|
||||
|
||||
function submitHandler() {
|
||||
if (status.value === 'view') return
|
||||
submiting.value = true
|
||||
if (roleFormData.value.id != null) {
|
||||
RoleApi.modify(roleFormData.value)
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
const props = withDefaults(defineProps<{
|
||||
research?: () => void
|
||||
}>(), {
|
||||
research: () => {
|
||||
},
|
||||
})
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
||||
const formPanelProps = buildFormPanelProps<RoleTypes.SearchRoleResult>({
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
return Promise.resolve()
|
||||
} else {
|
||||
RoleApi.add(roleFormData.value)
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
status.value = 'modify'
|
||||
return RoleApi.detail(id!)
|
||||
.then(res => {
|
||||
return {
|
||||
...res.data,
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
doSubmit(data) {
|
||||
if (status.value === 'add') {
|
||||
return RoleApi.add(data)
|
||||
.then(props.research)
|
||||
} else {
|
||||
return RoleApi.modify(data)
|
||||
.then(props.research)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
formPanelProps.title = status.value === 'add' ? '新建角色' : '修改角色'
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
open(data: RoleTypes.SearchRoleResult = {}) {
|
||||
showDialog.value = true
|
||||
if (!Strings.isBlank(data.id)) {
|
||||
status.value = 'modify'
|
||||
RoleApi.detail(data.id!)
|
||||
.then(res => {
|
||||
roleFormData.value = res.data
|
||||
})
|
||||
} else {
|
||||
status.value = 'add'
|
||||
roleFormData.value = data
|
||||
}
|
||||
open(data?: RoleTypes.SearchRoleResult) {
|
||||
formPanelIns.value?.open(data?.id)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,39 +1,51 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{searchForm}">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #highFormItem="formData">
|
||||
<ElFormItem label="任务名称">
|
||||
<ElInput
|
||||
v-model="searchForm.taskName"
|
||||
v-model="formData.taskName"
|
||||
placeholder="任务名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="任务执行函数">
|
||||
<ElFormItem label="执行函数">
|
||||
<ElInput
|
||||
v-model="searchForm.fn"
|
||||
placeholder="任务执行函数"/>
|
||||
v-model="formData.fn"
|
||||
placeholder="执行函数"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="调度方式">
|
||||
<ElSelect
|
||||
v-model="searchForm.scheduleType"
|
||||
clearable placeholder="请选择调度方式" style="width: 150px" @change="paging" @clear="paging">
|
||||
v-model="formData.scheduleType"
|
||||
clearable placeholder="请选择调度方式" @change="research" @clear="research">
|
||||
<ElOption v-for="item in scheduleTypeList" :key="item.value" :label="item.label" :value="item.value"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="内部任务">
|
||||
<ElCheckbox
|
||||
@change="research"
|
||||
v-model="searchForm.builtin"
|
||||
placeholder="内部任务"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="!searchForm.builtin" label="状态">
|
||||
<ElSelect v-model="searchForm.disabled" clearable placeholder="请选择状态" style="width: 150px" @clear="paging">
|
||||
|
||||
<ElFormItem v-if="!formData.builtin" label="状态">
|
||||
<ElSelect v-model="formData.disabled" clearable placeholder="请选择状态" @clear="research">
|
||||
<ElOption :value="true" label="禁用"/>
|
||||
<ElOption :value="false" label="启用"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
</template>
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElSwitch v-model="formData.builtin"
|
||||
active-text="系统任务"
|
||||
inactive-text="用户任务"
|
||||
@change="research"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="formData.taskName"
|
||||
placeholder="任务名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="formData.fn"
|
||||
placeholder="任务执行函数"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
<ElTableColumn label="任务名称" prop="taskName"/>
|
||||
|
|
@ -53,49 +65,57 @@
|
|||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
<ElTableColumn label="是否禁用" width="180">
|
||||
<template #default="scope">
|
||||
<span>
|
||||
{{ scope.row.disabled ? '是' : '否' }}
|
||||
</span>
|
||||
<ElTableColumn label="是否禁用" prop="disabled" width="100">
|
||||
<template #default="{row}">
|
||||
<ElSwitch v-model="row.disabled" :disabled="row.builtin" @change="disabledUserHandler($event,row.id)"/>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
<ElTableColumn label="备注" prop="memo"/>
|
||||
</template>
|
||||
<TaskForm ref="taskForm" @edit-succ="research"/>
|
||||
<TaskForm ref="taskForm" :research="research"/>
|
||||
<ScheduleRecodePanel ref="scheduleRecodePanel"/>
|
||||
</FormPage>
|
||||
</ATablePage>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TaskApi from '@/pages/sys/task/task-api.ts'
|
||||
import TaskForm from '@/pages/sys/task/TaskForm.vue'
|
||||
import ScheduleRecodePanel from '@/pages/sys/task/schedule-recode/ScheduleRecodePanel.vue'
|
||||
import Times from '@/common/utils/times.ts'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
}
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildTablePageProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const taskFormIns = useTemplateRef<InstanceType<typeof TaskForm>>('taskForm')
|
||||
const scheduleRecodePanelIns = useTemplateRef<InstanceType<typeof ScheduleRecodePanel>>('scheduleRecodePanel')
|
||||
const scheduleTypeList = [
|
||||
{value: 'Manually', label: '手动'},
|
||||
{value: 'Fixed', label: '固定周期'},
|
||||
{value: 'Cron', label: '自定义'},
|
||||
]
|
||||
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<TaskTypes.SearchTaskResult>>({
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
const tablePageProps = buildTablePageProps<TaskTypes.SearchTaskParam, TaskTypes.SearchTaskResult>({
|
||||
pageLayout: {
|
||||
searchFormHeight: '64px',
|
||||
},
|
||||
searchForm: {
|
||||
highForm: {
|
||||
contentWidth: 200,
|
||||
},
|
||||
simpleForm: {
|
||||
colCount: 3,
|
||||
},
|
||||
paging: TaskApi.paging,
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
taskFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
foldLimit: 4,
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
|
|
@ -108,25 +128,10 @@ const actionColumn = reactive<ActionColumnType<TaskTypes.SearchTaskResult>>({
|
|||
taskFormIns.value?.open(row)
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip({row}) {
|
||||
return row.disabled ? '启用' : '禁用'
|
||||
},
|
||||
show({row}) {
|
||||
return !row.builtin
|
||||
},
|
||||
icon: 'Edit',
|
||||
action({row}) {
|
||||
return TaskApi.disable(row.id!, !row.disabled!)
|
||||
.then(() => {
|
||||
ElMessage.success(row.disabled ? '启用成功' : '禁用成功')
|
||||
return true
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: '执行一次',
|
||||
icon: 'Edit',
|
||||
icon: 'putongzhihang',
|
||||
type: 'primary',
|
||||
show({row}) {
|
||||
return !row.disabled
|
||||
},
|
||||
|
|
@ -139,7 +144,8 @@ const actionColumn = reactive<ActionColumnType<TaskTypes.SearchTaskResult>>({
|
|||
},
|
||||
{
|
||||
tooltip: '调度记录',
|
||||
icon: 'Edit',
|
||||
type: 'default',
|
||||
icon: 'zhihangjilu',
|
||||
action({row}) {
|
||||
scheduleRecodePanelIns.value?.open(row.id!)
|
||||
},
|
||||
|
|
@ -163,19 +169,27 @@ const actionColumn = reactive<ActionColumnType<TaskTypes.SearchTaskResult>>({
|
|||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
const leftTools: ToolType[] = [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
taskFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function paging(param: TaskTypes.SearchTaskParam) {
|
||||
return TaskApi.paging(param)
|
||||
function disabledUserHandler(val: string | number | boolean, id: string) {
|
||||
TaskApi.disable(id, val as boolean)
|
||||
.then(() => {
|
||||
ElMessage.success(val ? '禁用成功' : '启用成功')
|
||||
research()
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
function research() {
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
const scheduleRecodePanelIns = useTemplateRef<InstanceType<typeof ScheduleRecodePanel>>('scheduleRecodePanel')
|
||||
const scheduleTypeList = [
|
||||
{value: 'Manually', label: '手动'},
|
||||
{value: 'Fixed', label: '固定周期'},
|
||||
{value: 'Cron', label: '自定义'},
|
||||
]
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,54 +1,62 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close width="25vw" @close="dialogCloseHandler">
|
||||
<ElForm :model="taskFormData" class="sys_task-form">
|
||||
<AFormPanel
|
||||
ref="formPanel"
|
||||
v-bind="formPanelProps">
|
||||
<template #default="formData">
|
||||
<div class="form-items">
|
||||
<ElFormItem label="任务名称">
|
||||
<ElInput v-model="taskFormData.taskName" placeholder="任务名称"/>
|
||||
<ElInput v-model="formData.taskName" placeholder="任务名称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="任务执行函数">
|
||||
<ElSelect v-model="taskFormData.fn" placeholder="请选择任务执行函数">
|
||||
<ElFormItem label="执行函数">
|
||||
<ElSelect v-model="formData.fn" placeholder="请选择任务执行函数">
|
||||
<ElOption v-for="item in fnList" :key="item.fn" :label="item.fn" :value="item.fn!"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="日志等级">
|
||||
<ElSelect v-model="taskFormData.logLevel" placeholder="请选择日志等级">
|
||||
<ElSelect v-model="formData.logLevel" placeholder="请选择日志等级">
|
||||
<ElOption v-for="item in logLevelList" :key="item.value" :label="item.label" :value="item.value"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="调度方式">
|
||||
<ElSelect v-model="taskFormData.scheduleType" placeholder="请选择调度方式" @change="scheduleTypeChange">
|
||||
<ElSelect v-model="formData.scheduleType" placeholder="请选择调度方式">
|
||||
<ElOption v-for="item in scheduleTypeList" :key="item.value" :label="item.label" :value="item.value"/>
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="taskFormData.scheduleType === 'Cron'" label="调度配置">
|
||||
<Cron v-model="taskFormData.scheduleConf" placeholder="调度配置"/>
|
||||
<ElFormItem v-if="formData.scheduleType === 'Cron'" label="调度配置">
|
||||
<Cron v-model="formData.scheduleConf" placeholder="调度配置"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-else-if="taskFormData.scheduleType === 'Fixed'" label="调度配置">
|
||||
<ElInput v-model="taskFormData.scheduleConf" placeholder="调度配置">
|
||||
<ElFormItem v-else-if="formData.scheduleType === 'Fixed'" label="调度配置">
|
||||
<ElInput v-model="formData.scheduleConf" placeholder="调度配置">
|
||||
<template #suffix>周期(秒)</template>
|
||||
</ElInput>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="是否禁用">
|
||||
<ElSwitch v-model="taskFormData.disabled" active-text="禁用" inactive-text="启用"/>
|
||||
<ElSwitch v-model="formData.disabled" active-text="禁用" inactive-text="启用"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="备注">
|
||||
<ElInput v-model="taskFormData.memo" placeholder="备注"/>
|
||||
<ElInput v-model="formData.memo" placeholder="备注"/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</AFormPanel>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TaskApi from '@/pages/sys/task/task-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import Cron from '@/pages/sys/task/cron/Cron.vue'
|
||||
import AFormPanel, {
|
||||
type AFormPanelInstance,
|
||||
buildFormPanelProps,
|
||||
} from '@/components/a-form-panel/AFormPanel.tsx'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
const props = withDefaults(defineProps<{
|
||||
research?: () => void
|
||||
}>(), {
|
||||
research: () => {
|
||||
},
|
||||
})
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
||||
const scheduleTypeList = [
|
||||
{value: 'Manually', label: '手动'},
|
||||
{value: 'Fixed', label: '固定周期'},
|
||||
|
|
@ -61,73 +69,66 @@ const logLevelList = [
|
|||
{value: 'ERROR', label: '错误'},
|
||||
{value: 'OFF', label: '关闭'},
|
||||
]
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||
let taskFormData = ref<TaskTypes.SearchTaskResult>({})
|
||||
const fnList = ref<TaskTypes.FnHandle[]>([])
|
||||
|
||||
function dialogCloseHandler() {
|
||||
taskFormData.value = {}
|
||||
}
|
||||
|
||||
function scheduleTypeChange(val: string) {
|
||||
if (val === 'Manually') {
|
||||
taskFormData.value.scheduleConf = ''
|
||||
} else if (val === 'Fixed') {
|
||||
taskFormData.value.scheduleConf = '1'
|
||||
} else if (val === 'Cron') {
|
||||
taskFormData.value.scheduleConf = '* * * * * ?'
|
||||
}
|
||||
}
|
||||
|
||||
function submitHandler() {
|
||||
if (status.value === 'view') return
|
||||
submiting.value = true
|
||||
if (taskFormData.value.id != null) {
|
||||
TaskApi.modify(taskFormData.value)
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
const formPanelProps = buildFormPanelProps<TaskTypes.SearchTaskResult>({
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
return Promise.resolve({
|
||||
scheduleConf: '* * * * * ?',
|
||||
scheduleType: 'Manually',
|
||||
logLevel: 'DEBUG',
|
||||
disabled: false,
|
||||
})
|
||||
} else {
|
||||
TaskApi.add(taskFormData.value)
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
status.value = 'modify'
|
||||
return TaskApi.detail(id!).then((res) => res.data)
|
||||
}
|
||||
},
|
||||
doSubmit(data) {
|
||||
if (status.value === 'add') {
|
||||
return TaskApi.add(data)
|
||||
.then(props.research)
|
||||
} else {
|
||||
return TaskApi.modify(data)
|
||||
.then(props.research)
|
||||
}
|
||||
|
||||
},
|
||||
watchForm: {
|
||||
formItems: [],
|
||||
callback(formData) {
|
||||
const val = formData.scheduleType
|
||||
if (val === 'Manually') {
|
||||
formData.scheduleConf = ''
|
||||
} else if (val === 'Fixed') {
|
||||
formData.scheduleConf = '1'
|
||||
} else if (val === 'Cron') {
|
||||
formData.scheduleConf = '* * * * * ?'
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
watchEffect(() => {
|
||||
formPanelProps.title = status.value === 'add' ? '新建任务' : '修改任务'
|
||||
})
|
||||
defineExpose({
|
||||
open(data: TaskTypes.SearchTaskResult = {}) {
|
||||
showDialog.value = true
|
||||
open(data?: TaskTypes.SearchTaskResult) {
|
||||
formPanelIns.value?.open(data?.id)
|
||||
TaskApi.fn().then(res => {
|
||||
fnList.value = res.data
|
||||
})
|
||||
if (!Strings.isBlank(data.id)) {
|
||||
status.value = 'modify'
|
||||
TaskApi.detail(data.id!).then((res) => {
|
||||
taskFormData.value = res.data
|
||||
})
|
||||
} else {
|
||||
status.value = 'add'
|
||||
data.scheduleConf = '* * * * * ?'
|
||||
taskFormData.value = data
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.sys_task-form {
|
||||
padding 20px
|
||||
.form-items {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: "picture ." \
|
||||
"picture .";
|
||||
|
||||
:deep(.el-form-item) {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { elIcons } from '@/common/element/element.ts'
|
||||
import CronPanel from '@/pages/sys/task/cron/cron-panel/CronPanel.vue'
|
||||
import { useCronStore } from '@/pages/sys/task/cron/cron-store.ts'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string
|
||||
|
|
@ -41,12 +42,11 @@ function openPanel() {
|
|||
<ElButton :icon="elIcons.Timer" type="text" @click="openPanel"/>
|
||||
</template>
|
||||
</ElInput>
|
||||
<ElDialog v-model="showDialog"
|
||||
<ADialog v-model:show="showDialog"
|
||||
title="配置面板"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close width="50vw">
|
||||
width="50vw">
|
||||
<CronPanel/>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@
|
|||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<div class="tool-bar">
|
||||
<!-- <div class="tool-bar">
|
||||
<ElButton :icon="elIcons.Filter" type="default" @click="showSearchForm = !showSearchForm"/>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<ElTable v-loading="searching" :data="tableData"
|
||||
cell-class-name="table-cell"
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
<ADialog v-model:show="showDialog"
|
||||
:closed="dialogCloseHandler"
|
||||
width="80vw"
|
||||
@close="dialogCloseHandler">
|
||||
title="执行日志">
|
||||
<ExecuteLog :schedule-id="scheduleId"/>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">关闭</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ExecuteLog from '@/pages/sys/task/execute-log/ExecuteLog.vue'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const scheduleId = ref<string>('')
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@
|
|||
<ElButton :icon="elIcons.Refresh" :loading="searching" @click="reset">重置</ElButton>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<div class="tool-bar">
|
||||
<!-- <div class="tool-bar">
|
||||
<ElButton :icon="elIcons.Filter" type="default" @click="showSearchForm = !showSearchForm"/>
|
||||
</div>
|
||||
</div> -->
|
||||
<ElTable v-loading="searching" :data="tableData"
|
||||
cell-class-name="table-cell"
|
||||
class="table-list"
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
<ADialog v-model:show="showDialog"
|
||||
title="执行记录"
|
||||
width="80vw">
|
||||
<ScheduleRecode :task-id="taskId"/>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">关闭</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import ScheduleRecode from '@/pages/sys/task/schedule-recode/ScheduleRecode.vue'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const showDialog = ref(false)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
@close="dialogCloseHandler"
|
||||
destroy-on-close
|
||||
width="700">
|
||||
<ADialog v-model:show="showDialog"
|
||||
:closed="dialogCloseHandler"
|
||||
title="分配角色" width="700px">
|
||||
<ElTransfer
|
||||
v-model="rightValue"
|
||||
:button-texts="['解绑', '绑定']"
|
||||
|
|
@ -36,7 +34,7 @@
|
|||
<ElButton @click="showDialog = false">取消</ElButton>
|
||||
<ElButton :disabled="rightValue.length <= 0" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</ADialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleApi from '@/pages/sys/role/role-api.ts'
|
||||
|
|
@ -46,6 +44,7 @@ import {
|
|||
type TransferDataItem,
|
||||
} from 'element-plus'
|
||||
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||
import ADialog from '@/components/a-dialog/ADialog.vue'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
|
|
@ -60,6 +59,7 @@ function dialogCloseHandler() {
|
|||
allRoles.value = []
|
||||
rightValue.value = []
|
||||
}
|
||||
|
||||
function filterMethod(query: string, item: TransferDataItem) {
|
||||
return Strings.isBlank(query) || (item as RoleTypes.SearchRoleResult).roleCode!.includes(query) || (item as RoleTypes.SearchRoleResult).roleName!.includes(query)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
<template>
|
||||
<FormPage
|
||||
ref="formPage"
|
||||
:action-column="actionColumn"
|
||||
:left-tools="leftTools"
|
||||
:paging="paging">
|
||||
<template #searchFormItem="{searchForm}">
|
||||
<ElFormItem label="姓名">
|
||||
<ATablePage
|
||||
ref="tablePage"
|
||||
v-bind="tablePageProps">
|
||||
<template #simpleFormItem="formData">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.nickname"
|
||||
v-model="formData.nickname"
|
||||
placeholder="姓名"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="手机号">
|
||||
<ElFormItem>
|
||||
<ElInput
|
||||
v-model="searchForm.phone"
|
||||
v-model="formData.phone"
|
||||
placeholder="手机号"/>
|
||||
</ElFormItem>
|
||||
</template>
|
||||
<template #columns>
|
||||
<ElTableColumn label="姓名" prop="nickname"/>
|
||||
<ElTableColumn label="头像" prop="avatar" width="60">
|
||||
<template #default="{row}">
|
||||
<ElImage :preview-src-list="Strings.isBlank(row.avatar)?[]:[AppApi.fileUrl(row.avatar)]" :src="Strings.isBlank(row.avatar)?Avatar:AppApi.fileUrl(row.avatar)" class="avatar" preview-teleported>
|
||||
|
|
@ -29,27 +26,29 @@
|
|||
</ElImage>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
||||
<ElTableColumn label="姓名" prop="nickname"/>
|
||||
<ElTableColumn label="联系电话" prop="phone"/>
|
||||
<ElTableColumn label="登录手机号" prop="account.phone"/>
|
||||
<!-- <ElTableColumn label="登录手机号" prop="account.phone"/> -->
|
||||
<ElTableColumn label="用户名" prop="account.username"/>
|
||||
<ElTableColumn label="微信标识" prop="account.wechatOpenid"/>
|
||||
<ElTableColumn label="已授权客户端" prop="account.clientCode" width="110">
|
||||
<ElTableColumn label="微信标识" prop="account.wechatOpenid" width="180"/>
|
||||
<ElTableColumn label="已授权客户端" prop="account.clientCode" width="130">
|
||||
<template #default="{row}">
|
||||
<ElCheckboxGroup v-model="row.account.clients" @change="clientChangeHandler($event,row)">
|
||||
<ElCheckbox v-for="client in ClientUtil.clients" :key="client.val" :disabled="row.id == '1' && client.val === 1" :label="client.txt" :value="client.val"/>
|
||||
</ElCheckboxGroup>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="是否禁用" prop="account.disabled">
|
||||
<ElTableColumn label="是否禁用" prop="account.disabled" width="100">
|
||||
<template #default="{row}">
|
||||
<ElSwitch v-model="row.account.disabled" :disabled="row.id == '1'" @change="disabledUserHandler($event,row.id)"/>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="注册时间" prop="account.regdate" width="170"/>
|
||||
<ElTableColumn label="注册时间" prop="account.regdate" width="180"/>
|
||||
</template>
|
||||
<UserForm ref="userForm" @edit-succ="paging"/>
|
||||
<UserForm ref="userForm" :research="research"/>
|
||||
<BindRole ref="bindRole"/>
|
||||
</FormPage>
|
||||
</ATablePage>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||
|
|
@ -63,19 +62,91 @@ import BindRole from '@/pages/sys/user/BindRole.vue'
|
|||
import ClientUtil from '@/common/utils/client-util.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import Avatar from '@/assets/images/avatar.png'
|
||||
import FormPage from '@/components/page/FormPage.vue'
|
||||
import type {
|
||||
ActionColumnType,
|
||||
ToolType,
|
||||
} from '@/components/page/a-page-type.ts'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import ATablePage, {
|
||||
type ATablePageInstance,
|
||||
buildTablePageProps,
|
||||
} from '@/components/a-page/a-table-page/ATablePage.tsx'
|
||||
|
||||
const formPageIns = useTemplateRef<ComponentExposed<typeof FormPage>>('formPage')
|
||||
const userFormIns = useTemplateRef<InstanceType<typeof UserForm>>('userForm')
|
||||
const bindRoleIns = useTemplateRef<InstanceType<typeof BindRole>>('bindRole')
|
||||
const tablePageIns = useTemplateRef<ATablePageInstance>('tablePage')
|
||||
const tablePageProps = buildTablePageProps<UserTypes.SearchUserParam, UserTypes.SearchUserResult>({
|
||||
pageLayout: {
|
||||
enableHighForm: false,
|
||||
},
|
||||
searchForm: {
|
||||
simpleForm: {
|
||||
colCount: 2,
|
||||
},
|
||||
paging(param) {
|
||||
return UserApi.paging(param)
|
||||
.then(res => {
|
||||
(res.data?.records ?? []).map(it => {
|
||||
it.account.clients = ClientUtil.getClients(it.account.clientCode!).map(it => it.val)
|
||||
return it
|
||||
})
|
||||
return res
|
||||
})
|
||||
},
|
||||
},
|
||||
toolBar: {
|
||||
leftTools: [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
userFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
table: {
|
||||
actionColumn: {
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
icon: 'Edit',
|
||||
type: 'success',
|
||||
action({row}) {
|
||||
userFormIns.value?.open(row)
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: '权限',
|
||||
icon: 'gongnengquanxian',
|
||||
type: 'warning',
|
||||
action({row}) {
|
||||
bindRoleIns.value?.open(row.id!)
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: '重置密码',
|
||||
icon: 'zhongzhimima',
|
||||
type: 'danger',
|
||||
confirm: {
|
||||
title: '确定重置密码?',
|
||||
},
|
||||
show({row}) {
|
||||
return row.id != '1'
|
||||
},
|
||||
action({row}) {
|
||||
if (row.id == '1') {
|
||||
ElMessage.error('不能修改管理员')
|
||||
return
|
||||
}
|
||||
UserApi.resetPasswd(row.id!)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg)
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
function research() {
|
||||
formPageIns.value?.doSearch()
|
||||
tablePageIns.value?.doSearch()
|
||||
}
|
||||
|
||||
function clientChangeHandler(clients: CheckboxValueType[], data: UserTypes.SearchUserResult) {
|
||||
|
|
@ -98,62 +169,6 @@ function disabledUserHandler(val: string | number | boolean, id: string) {
|
|||
})
|
||||
}
|
||||
|
||||
const actionColumn = reactive<ActionColumnType<UserTypes.SearchUserResult>>({
|
||||
tableActions: [
|
||||
{
|
||||
tooltip: '编辑',
|
||||
icon: 'Edit',
|
||||
type: 'success',
|
||||
action({row}) {
|
||||
userFormIns.value?.open(row)
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: '权限',
|
||||
icon: 'Edit',
|
||||
action({row}) {
|
||||
bindRoleIns.value?.open(row.id!)
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: '重置密码',
|
||||
icon: 'Edit',
|
||||
show({row}) {
|
||||
return row.id != '1'
|
||||
},
|
||||
action({row}) {
|
||||
if (row.id == '1') {
|
||||
ElMessage.error('不能修改管理员')
|
||||
return
|
||||
}
|
||||
UserApi.resetPasswd(row.id!)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg)
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
const leftTools: ToolType[] = [
|
||||
{
|
||||
icon: 'Plus',
|
||||
label: '新建',
|
||||
action() {
|
||||
userFormIns.value?.open()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
function paging(param: UserTypes.SearchUserParam) {
|
||||
return UserApi.paging(param)
|
||||
.then(res => {
|
||||
(res.data?.records ?? []).map(it => {
|
||||
it.account.clients = ClientUtil.getClients(it.account.clientCode!).map(it => it.val)
|
||||
return it
|
||||
})
|
||||
return res
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.avatar {
|
||||
|
|
|
|||
|
|
@ -1,139 +1,130 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
@close="dialogCloseHandler"
|
||||
destroy-on-close
|
||||
width="25vw">
|
||||
<ElForm :model="userFormData"
|
||||
class="sys_user-form"
|
||||
>
|
||||
<ElFormItem label="姓名">
|
||||
<ElInput
|
||||
:readonly="userFormData.id=='1'"
|
||||
v-model="userFormData.nickname"
|
||||
|
||||
placeholder="姓名"/>
|
||||
</ElFormItem>
|
||||
<AFormPanel
|
||||
ref="formPanel"
|
||||
v-bind="formPanelProps">
|
||||
<template #default="formData">
|
||||
<div class="form-items">
|
||||
<ElFormItem label="头像">
|
||||
<Uploader
|
||||
v-model:file="userFormData.avatar"
|
||||
|
||||
:upload-props="{
|
||||
accept: 'image/*',
|
||||
listType:'picture'
|
||||
}">
|
||||
<ElButton>点击上传头像</ElButton>
|
||||
</Uploader>
|
||||
ref="uploader"
|
||||
v-model:file="formData.avatar"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="姓名">
|
||||
<ElInput
|
||||
v-model="formData.nickname"
|
||||
:readonly="formData.id=='1'"
|
||||
placeholder="姓名"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="联系电话">
|
||||
<ElInput
|
||||
v-model="userFormData.phone"
|
||||
|
||||
v-model="formData.phone"
|
||||
placeholder="联系电话"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="status === 'add'" label="用户名">
|
||||
<ElInput
|
||||
v-model="userFormData.account.username"
|
||||
placeholder="用户名"/>
|
||||
<ElInput v-model="formData.account.username" placeholder="用户名"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="status === 'add'" label="密码">
|
||||
<ElInput
|
||||
v-model="userFormData.account.secret"
|
||||
v-model="formData.account.secret"
|
||||
autocomplete="new-password"
|
||||
placeholder="密码"
|
||||
show-password
|
||||
type="password"/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
<ElButton v-if="status !== 'view'" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</AFormPanel>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import Uploader from '@/components/uploader/Uploader.vue'
|
||||
import AFormPanel, {
|
||||
type AFormPanelInstance,
|
||||
buildFormPanelProps,
|
||||
} from '@/components/a-form-panel/AFormPanel.tsx'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||
const userFormData = ref<UserTypes.SearchUserResult>({
|
||||
const props = withDefaults(defineProps<{
|
||||
research?: () => void
|
||||
}>(), {
|
||||
research: () => {
|
||||
},
|
||||
})
|
||||
const formPanelIns = useTemplateRef<AFormPanelInstance>('formPanel')
|
||||
const uploaderIns = useTemplateRef<InstanceType<typeof Uploader>>('uploader')
|
||||
|
||||
const status = ref<'add' | 'modify'>('add')
|
||||
|
||||
const formPanelProps = buildFormPanelProps<UserTypes.SearchUserResult>({
|
||||
detailsLoader(id?: string) {
|
||||
if (Strings.isBlank(id)) {
|
||||
status.value = 'add'
|
||||
return Promise.resolve({
|
||||
account: {
|
||||
username: '',
|
||||
secret: '',
|
||||
},
|
||||
})
|
||||
|
||||
function dialogCloseHandler() {
|
||||
userFormData.value = {
|
||||
account: {
|
||||
username: '',
|
||||
secret: '',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function submitHandler() {
|
||||
if (status.value === 'view') return
|
||||
submiting.value = true
|
||||
if (userFormData.value.id != null) {
|
||||
const {id, nickname, avatar, email, phone} = userFormData.value
|
||||
UserApi.modify({id, nickname, avatar, email, phone})
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
} as UserTypes.SearchUserResult)
|
||||
} else {
|
||||
const {nickname, avatar, email, phone, account} = userFormData.value
|
||||
UserApi.add({nickname, avatar, email, phone, account})
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open(data?: UserTypes.SearchUserResult) {
|
||||
showDialog.value = true
|
||||
if (data != null && !Strings.isBlank(data.id)) {
|
||||
status.value = 'modify'
|
||||
UserApi.detail(data.id!)
|
||||
return UserApi.detail(id!)
|
||||
.then(res => {
|
||||
userFormData.value = {
|
||||
if (res.data.avatar != null) uploaderIns.value?.setDefaultFiles([ res.data.avatar ])
|
||||
return {
|
||||
...res.data, account: {},
|
||||
}
|
||||
})
|
||||
} else {
|
||||
status.value = 'add'
|
||||
userFormData.value = {
|
||||
}
|
||||
},
|
||||
defaultFormData: {
|
||||
account: {
|
||||
username: '',
|
||||
secret: '',
|
||||
},
|
||||
},
|
||||
doSubmit(data) {
|
||||
if (status.value === 'add') {
|
||||
const {nickname, avatar, email, phone, account} = data
|
||||
return UserApi.add({nickname, avatar, email, phone, account})
|
||||
.then(props.research)
|
||||
} else {
|
||||
const {id, nickname, avatar, email, phone} = data
|
||||
return UserApi.modify({id, nickname, avatar, email, phone})
|
||||
.then(props.research)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
watchEffect(() => {
|
||||
formPanelProps.title = status.value === 'add' ? '新建用户' : '修改用户'
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
open(data?: UserTypes.SearchUserResult) {
|
||||
formPanelIns.value?.open(data?.id)
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.sys_user-form {
|
||||
padding 20px
|
||||
.form-items {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: "picture ." \
|
||||
"picture .";
|
||||
|
||||
:deep(.el-form-item) {
|
||||
&:first-child {
|
||||
align-items: start;
|
||||
grid-area: picture
|
||||
max-width 300px
|
||||
|
||||
.el-form-item__content {
|
||||
justify-content center
|
||||
}
|
||||
|
||||
.avatar-uploader {
|
||||
width 100%
|
||||
.el-form-item__error {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue