Conflicts:
	src/views/infra/fileConfig/fileConfig.data.ts
	src/views/system/sms/smsChannel/sms.channel.data.ts
This commit is contained in:
YunaiV 2023-03-17 01:36:21 +08:00
commit d73b8431a1
29 changed files with 518 additions and 524 deletions

View File

@ -1,7 +1,7 @@
import request from '@/config/axios' import request from '@/config/axios'
export interface NoticeVO { export interface NoticeVO {
id: number id: number | undefined
title: string title: string
type: number type: number
content: string content: string
@ -11,32 +11,27 @@ export interface NoticeVO {
createTime: Date createTime: Date
} }
export interface NoticePageReqVO extends PageParam {
title?: string
status?: number
}
// 查询公告列表 // 查询公告列表
export const getNoticePageApi = (params: NoticePageReqVO) => { export const getNoticePage = (params: PageParam) => {
return request.get({ url: '/system/notice/page', params }) return request.get({ url: '/system/notice/page', params })
} }
// 查询公告详情 // 查询公告详情
export const getNoticeApi = (id: number) => { export const getNotice = (id: number) => {
return request.get({ url: '/system/notice/get?id=' + id }) return request.get({ url: '/system/notice/get?id=' + id })
} }
// 新增公告 // 新增公告
export const createNoticeApi = (data: NoticeVO) => { export const createNotice = (data: NoticeVO) => {
return request.post({ url: '/system/notice/create', data }) return request.post({ url: '/system/notice/create', data })
} }
// 修改公告 // 修改公告
export const updateNoticeApi = (data: NoticeVO) => { export const updateNotice = (data: NoticeVO) => {
return request.put({ url: '/system/notice/update', data }) return request.put({ url: '/system/notice/update', data })
} }
// 删除公告 // 删除公告
export const deleteNoticeApi = (id: number) => { export const deleteNotice = (id: number) => {
return request.delete({ url: '/system/notice/delete?id=' + id }) return request.delete({ url: '/system/notice/delete?id=' + id })
} }

View File

@ -53,5 +53,5 @@ export const getSmsLogPageApi = (params: SmsLogPageReqVO) => {
// 导出短信日志 // 导出短信日志
export const exportSmsLogApi = (params: SmsLogExportReqVO) => { export const exportSmsLogApi = (params: SmsLogExportReqVO) => {
return request.download({ url: '/system/sms-log/export', params }) return request.download({ url: '/system/sms-log/export-excel', params })
} }

View File

@ -45,17 +45,22 @@ const tabsList = [
const pageList = computed(() => { const pageList = computed(() => {
if (currentPage.value === 1) { if (currentPage.value === 1) {
return copyIconList[currentActiveType.value] return copyIconList[currentActiveType.value]
.filter((v) => v.includes(filterValue.value)) ?.filter((v) => v.includes(filterValue.value))
.slice(currentPage.value - 1, pageSize.value) .slice(currentPage.value - 1, pageSize.value)
} else { } else {
return copyIconList[currentActiveType.value] return copyIconList[currentActiveType.value]
.filter((v) => v.includes(filterValue.value)) ?.filter((v) => v.includes(filterValue.value))
.slice( .slice(
pageSize.value * (currentPage.value - 1), pageSize.value * (currentPage.value - 1),
pageSize.value * (currentPage.value - 1) + pageSize.value pageSize.value * (currentPage.value - 1) + pageSize.value
) )
} }
}) })
const iconCount = computed(() => {
return copyIconList[currentActiveType.value] == undefined
? 0
: copyIconList[currentActiveType.value].length
})
const iconItemStyle = computed((): ParameterCSSProperties => { const iconItemStyle = computed((): ParameterCSSProperties => {
return (item) => { return (item) => {
@ -159,7 +164,7 @@ watch(
<ElPagination <ElPagination
small small
:total="copyIconList[currentActiveType].length as unknown as number" :total="iconCount"
:page-size="pageSize" :page-size="pageSize"
:current-page="currentPage" :current-page="currentPage"
background background

View File

@ -128,7 +128,7 @@ const getColumnsConfig = (options: XTableProps) => {
proxyForm = true proxyForm = true
options.formConfig = { options.formConfig = {
enabled: true, enabled: true,
titleWidth: 100, titleWidth: 180,
titleAlign: 'right', titleAlign: 'right',
items: allSchemas.searchSchema items: allSchemas.searchSchema
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="my-process-designer"> <div class="my-process-designer">
<div class="my-process-designer__header"> <div class="my-process-designer__header" style="display: table-row-group; z-index: 999">
<slot name="control-header"></slot> <slot name="control-header"></slot>
<template v-if="!$slots['control-header']"> <template v-if="!$slots['control-header']">
<ElButtonGroup key="file-control"> <ElButtonGroup key="file-control">

View File

@ -3,10 +3,8 @@
<el-form label-width="90px"> <el-form label-width="90px">
<el-form-item label="回路特性"> <el-form-item label="回路特性">
<el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType"> <el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType">
<!--bpmn:MultiInstanceLoopCharacteristics-->
<el-option label="并行多重事件" value="ParallelMultiInstance" /> <el-option label="并行多重事件" value="ParallelMultiInstance" />
<el-option label="时序多重事件" value="SequentialMultiInstance" /> <el-option label="时序多重事件" value="SequentialMultiInstance" />
<!--bpmn:StandardLoopCharacteristics-->
<el-option label="循环事件" value="StandardLoop" /> <el-option label="循环事件" value="StandardLoop" />
<el-option label="无" value="Null" /> <el-option label="无" value="Null" />
</el-select> </el-select>

View File

@ -35,7 +35,7 @@ router.beforeEach(async (to, from, next) => {
const userStore = useUserStoreWithOut() const userStore = useUserStoreWithOut()
const permissionStore = usePermissionStoreWithOut() const permissionStore = usePermissionStoreWithOut()
if (!dictStore.getIsSetDict) { if (!dictStore.getIsSetDict) {
dictStore.setDictMap() await dictStore.setDictMap()
} }
if (!userStore.getIsSetUser) { if (!userStore.getIsSetUser) {
isRelogin.show = true isRelogin.show = true

45
src/utils/permission.ts Normal file
View File

@ -0,0 +1,45 @@
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
const { t } = useI18n() // 国际化
/**
*
* @param {Array} value
* @returns {Boolean}
*/
export function checkPermi(value: string[]) {
if (value && value instanceof Array && value.length > 0) {
const { wsCache } = useCache()
const permissionDatas = value
const all_permission = '*:*:*'
const permissions = wsCache.get(CACHE_KEY.USER).permissions
const hasPermission = permissions.some((permission) => {
return all_permission === permission || permissionDatas.includes(permission)
})
return !!hasPermission
} else {
console.error(t('permission.hasPermission'))
return false
}
}
/**
*
* @param {string[]} value
* @returns {Boolean}
*/
export function checkRole(value: string[]) {
if (value && value instanceof Array && value.length > 0) {
const { wsCache } = useCache()
const permissionRoles = value
const super_admin = 'admin'
const roles = wsCache.get(CACHE_KEY.USER).roles
const hasRole = roles.some((role) => {
return super_admin === role || permissionRoles.includes(role)
})
return !!hasRole
} else {
console.error(t('permission.hasRole'))
return false
}
}

View File

@ -10,7 +10,7 @@ export const rules = reactive({
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
primaryType: 'seq', primaryType: 'id',
primaryTitle: '表单编号', primaryTitle: '表单编号',
action: true, action: true,
columns: [ columns: [

View File

@ -250,7 +250,7 @@
name="bpmnFile" name="bpmnFile"
:data="importForm" :data="importForm"
> >
<el-icon class="el-icon--upload"><upload-filled /></el-icon> <Icon class="el-icon--upload" icon="ep:upload-filled" />
<div class="el-upload__text"> 将文件拖到此处 <em>点击上传</em> </div> <div class="el-upload__text"> 将文件拖到此处 <em>点击上传</em> </div>
<template #tip> <template #tip>
<div class="el-upload__tip" style="color: red"> <div class="el-upload__tip" style="color: red">

View File

@ -3,14 +3,15 @@ import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
primaryType: 'seq', primaryType: 'id',
primaryTitle: '日志编号', primaryTitle: '日志编号',
action: true, action: true,
actionWidth: '80px', actionWidth: '80px',
columns: [ columns: [
{ {
title: '链路追踪', title: '链路追踪',
field: 'traceId' field: 'traceId',
isTable: false
}, },
{ {
title: '用户编号', title: '用户编号',

View File

@ -3,7 +3,7 @@ import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
primaryType: 'seq', primaryType: 'id',
primaryTitle: '日志编号', primaryTitle: '日志编号',
action: true, action: true,
actionWidth: '300', actionWidth: '300',

View File

@ -8,7 +8,7 @@
<el-button size="small" type="primary" @click="showJson">生成JSON</el-button> <el-button size="small" type="primary" @click="showJson">生成JSON</el-button>
<el-button size="small" type="success" @click="showOption">生成Options</el-button> <el-button size="small" type="success" @click="showOption">生成Options</el-button>
<el-button size="small" type="danger" @click="showTemplate">生成组件</el-button> <el-button size="small" type="danger" @click="showTemplate">生成组件</el-button>
<el-button size="small" @click="changeLocale">中英切换</el-button> <!-- <el-button size="small" @click="changeLocale">中英切换</el-button> -->
</div> </div>
</el-col> </el-col>
<el-col> <el-col>
@ -19,9 +19,11 @@
<div ref="editor" v-if="dialogVisible"> <div ref="editor" v-if="dialogVisible">
<XTextButton style="float: right" :title="t('common.copy')" @click="copy(formValue)" /> <XTextButton style="float: right" :title="t('common.copy')" @click="copy(formValue)" />
<el-scrollbar height="580"> <el-scrollbar height="580">
<pre> <div v-highlight>
<code class="hljs">
{{ formValue }} {{ formValue }}
</pre> </code>
</div>
</el-scrollbar> </el-scrollbar>
</div> </div>
<span style="color: red" v-if="err">输入内容格式有误!</span> <span style="color: red" v-if="err">输入内容格式有误!</span>
@ -69,9 +71,9 @@ const showTemplate = () => {
type.value = 2 type.value = 2
formValue.value = makeTemplate() formValue.value = makeTemplate()
} }
const changeLocale = () => { // const changeLocale = () => {
console.info('changeLocale') // console.info('changeLocale')
} // }
/** 复制 **/ /** 复制 **/
const copy = async (text: string) => { const copy = async (text: string) => {

View File

@ -70,7 +70,7 @@ const detailData = ref() // 详情 Ref
// //
const handleDetail = async (row: JobLogApi.JobLogVO) => { const handleDetail = async (row: JobLogApi.JobLogVO) => {
// //
const res = JobLogApi.getJobLogApi(row.id) const res = await JobLogApi.getJobLogApi(row.id)
detailData.value = res detailData.value = res
dialogTitle.value = t('action.detail') dialogTitle.value = t('action.detail')
dialogVisible.value = true dialogVisible.value = true

View File

@ -11,7 +11,7 @@ export const rules = reactive({
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
primaryType: 'seq', primaryType: 'id',
primaryTitle: '任务编号', primaryTitle: '任务编号',
action: true, action: true,
actionWidth: '280px', actionWidth: '280px',

View File

@ -4,7 +4,7 @@ const { t } = useI18n()
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
primaryType: 'seq', primaryType: 'id',
primaryTitle: '日志编号', primaryTitle: '日志编号',
action: true, action: true,
columns: [ columns: [

View File

@ -0,0 +1,131 @@
<template>
<Dialog :title="modelTitle" v-model="modelVisible" width="800">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="80px"
v-loading="formLoading"
>
<el-form-item label="公告标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入公告标题" />
</el-form-item>
<el-form-item label="公告内容" prop="content">
<Editor :model-value="formData.content" height="150px" />
</el-form-item>
<el-form-item label="公告类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择公告类型" clearable>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_NOTICE_TYPE)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="formData.status" placeholder="请选择状态" clearable>
<el-option
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" placeholder="请输备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="modelVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import * as NoticeApi from '@/api/system/notice'
const { t } = useI18n() //
const message = useMessage() //
const modelVisible = ref(false) //
const modelTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
title: '',
type: undefined,
content: '',
status: undefined,
remark: ''
})
const formRules = reactive({
title: [{ required: true, message: '公告标题不能为空', trigger: 'blur' }],
type: [{ required: true, message: '公告类型不能为空', trigger: 'change' }],
status: [{ required: true, message: '状态不能为空', trigger: 'change' }],
content: [{ required: true, message: '公告内容不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const openModal = async (type: string, id?: number) => {
modelVisible.value = true
modelTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await NoticeApi.getNotice(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // openModal
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
//
formLoading.value = true
try {
const data = formData.value as unknown as NoticeApi.NoticeVO
if (formType.value === 'create') {
await NoticeApi.createNotice(data)
message.success(t('common.createSuccess'))
} else {
await NoticeApi.updateNotice(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
title: '',
type: undefined,
content: '',
status: undefined,
remark: ''
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,150 +1,159 @@
<template> <template>
<ContentWrap> <content-wrap>
<el-form ref="searchForm" :model="queryParms" :inline="true"> <!-- 搜索工作栏 -->
<el-form-item label="公告标题"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-input v-model="queryParms.title" /> <el-form-item label="公告标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入公告标题"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="公告状态" prop="status">
<el-select v-model="queryParms.status"> <el-select v-model="queryParams.status" placeholder="请选择公告状态" clearable>
<el-option label="全部" value="" /> <el-option
<el-option label="开启" :value="1" /> v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
<el-option label="关闭" :value="0" /> :key="parseInt(dict.value)"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="getList">Query</el-button> <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
@click="openModal('create')"
v-hasPermi="['system:notice:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div style="width: 100%; height: 600px">
<el-auto-resizer> <!-- 列表 -->
<template #default="{ height, width }"> <el-table v-loading="loading" :data="list" align="center">
<el-table-v2 <el-table-column label="公告编号" align="center" prop="id" />
:columns="columns" <el-table-column label="公告标题" align="center" prop="title" />
:data="tableData" <el-table-column label="公告类型" align="center" prop="type">
:width="width" <template #default="scope">
:height="height - 50" <dict-tag :type="DICT_TYPE.SYSTEM_NOTICE_TYPE" :value="scope.row.type" />
fixed
/>
</template> </template>
</el-auto-resizer> </el-table-column>
</div> <el-table-column label="状态" align="center" prop="status">
<div class="mt-2"> <template #default="scope">
<el-pagination <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
:current-page="queryParms.pageNo" </template>
:page-size="queryParms.pageSize" </el-table-column>
:page-sizes="[10, 20, 30, 50, 100]" <el-table-column
layout="total, sizes, prev, pager, next, jumper" label="创建时间"
:total="tableTotal" align="center"
@size-change="getList" prop="createTime"
@current-change="getList" width="180"
:formatter="dateFormatter"
/> />
</div> <el-table-column label="操作" align="center">
</ContentWrap> <template #default="scope">
<el-button
link
type="primary"
@click="openModal('update', scope.row.id)"
v-hasPermi="['system:notice:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['system:notice:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</content-wrap>
<!-- 表单弹窗添加/修改 -->
<notice-form ref="modalRef" @success="getList" />
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
import dayjs from 'dayjs' import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { Column, ElPagination, ElTableV2, TableV2FixedDir } from 'element-plus' import { dateFormatter } from '@/utils/formatTime'
import * as NoticeApi from '@/api/system/notice' import * as NoticeApi from '@/api/system/notice'
import { XTextButton } from '@/components/XButton'
import { DictTag } from '@/components/DictTag' import { DictTag } from '@/components/DictTag'
import NoticeForm from './form.vue'
const message = useMessage() //
const { t } = useI18n() // const { t } = useI18n() //
const columns: Column<any>[] = [ const loading = ref(true) //
{ const total = ref(0) //
key: 'id', const list = ref([]) //
dataKey: 'id', //{id:9527,name:'Mike'}id const queryParams = reactive({
title: 'id', //
width: 80, //
fixed: true //
},
{
key: 'title',
dataKey: 'title',
title: '公告标题',
width: 180
},
{
key: 'type',
dataKey: 'type',
title: '公告类型',
width: 180,
cellRenderer: ({ cellData: type }) => (
<DictTag type={DICT_TYPE.SYSTEM_NOTICE_TYPE} value={type}></DictTag>
)
},
{
key: 'status',
dataKey: 'status',
title: t('common.status'),
width: 180,
cellRenderer: ({ cellData: status }) => (
<DictTag type={DICT_TYPE.COMMON_STATUS} value={status}></DictTag>
)
},
{
key: 'content',
dataKey: 'content',
title: '公告内容',
width: 400,
cellRenderer: ({ cellData: content }) => <span v-html={content}></span>
},
{
key: 'createTime',
dataKey: 'createTime',
title: t('common.createTime'),
width: 180,
cellRenderer: ({ cellData: createTime }) => (
<>{dayjs(createTime).format('YYYY-MM-DD HH:mm:ss')}</>
)
},
{
key: 'actionbtns',
dataKey: 'actionbtns', //{id:9527,name:'Mike'}id
title: '操作', //
width: 160, //
fixed: TableV2FixedDir.RIGHT, //
align: 'center',
cellRenderer: ({ cellData: id }) => (
<>
<XTextButton
preIcon="ep:delete"
title={t('action.edit')}
onClick={handleUpdate.bind(this, id)}
></XTextButton>
<XTextButton
preIcon="ep:delete"
title={t('action.del')}
onClick={handleDelete.bind(this, id)}
></XTextButton>
</>
)
}
]
const tableData = ref([])
const tableTotal = ref(0)
const queryParms = reactive({
title: '', title: '',
type: undefined,
status: undefined, status: undefined,
pageNo: 1, pageNo: 1,
pageSize: 100 pageSize: 100
}) })
const queryFormRef = ref() //
/** 查询公告列表 */
const getList = async () => { const getList = async () => {
const res = await NoticeApi.getNoticePageApi(queryParms) loading.value = true
tableData.value = res.list try {
tableTotal.value = res.total const data = await NoticeApi.getNoticePage(queryParams)
}
list.value = data.list
const handleUpdate = (id) => { total.value = data.total
console.info(id) } finally {
} loading.value = false
}
const handleDelete = (id) => {
console.info(id)
} }
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList() getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const modalRef = ref()
const openModal = (type: string, id?: number) => {
modalRef.value.openModal(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await NoticeApi.deleteNotice(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script> </script>

View File

@ -1,148 +0,0 @@
<template>
<ContentWrap>
<!-- 列表 -->
<XTable @register="registerTable">
<!-- 操作新增 -->
<template #toolbar_buttons>
<XButton
type="primary"
preIcon="ep:zoom-in"
:title="t('action.add')"
v-hasPermi="['system:notice:create']"
@click="handleCreate()"
/>
</template>
<template #actionbtns_default="{ row }">
<!-- 操作修改 -->
<XTextButton
preIcon="ep:edit"
:title="t('action.edit')"
v-hasPermi="['system:notice:update']"
@click="handleUpdate(row.id)"
/>
<!-- 操作详情 -->
<XTextButton
preIcon="ep:view"
:title="t('action.detail')"
v-hasPermi="['system:notice:query']"
@click="handleDetail(row.id)"
/>
<!-- 操作删除 -->
<XTextButton
preIcon="ep:delete"
:title="t('action.del')"
v-hasPermi="['system:notice:delete']"
@click="deleteData(row.id)"
/>
</template>
</XTable>
</ContentWrap>
<!-- 弹窗 -->
<XModal id="noticeModel" v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) -->
<Form
ref="formRef"
v-if="['create', 'update'].includes(actionType)"
:schema="allSchemas.formSchema"
:rules="rules"
/>
<!-- 对话框(详情) -->
<Descriptions
v-if="actionType === 'detail'"
:schema="allSchemas.detailSchema"
:data="detailData"
>
<template #content="{ row }">
<Editor :model-value="row.content" :readonly="true" />
</template>
</Descriptions>
<template #footer>
<!-- 按钮保存 -->
<XButton
v-if="['create', 'update'].includes(actionType)"
type="primary"
:title="t('action.save')"
:loading="actionLoading"
@click="submitForm()"
/>
<!-- 按钮关闭 -->
<XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template>
</XModal>
</template>
<script setup lang="ts" name="Notice">
import type { FormExpose } from '@/components/Form'
// import
import * as NoticeApi from '@/api/system/notice'
import { rules, allSchemas } from './notice.data'
const { t } = useI18n() //
const message = useMessage() //
//
const [registerTable, { reload, deleteData }] = useXTable({
allSchemas: allSchemas,
getListApi: NoticeApi.getNoticePageApi,
deleteApi: NoticeApi.deleteNoticeApi
})
//
const dialogVisible = ref(false) //
const dialogTitle = ref('edit') //
const actionType = ref('') //
const actionLoading = ref(false) // Loading
const formRef = ref<FormExpose>() // Ref
const detailData = ref() // Ref
//
const setDialogTile = (type: string) => {
dialogTitle.value = t('action.' + type)
actionType.value = type
dialogVisible.value = true
}
//
const handleCreate = () => {
setDialogTile('create')
}
//
const handleUpdate = async (rowId: number) => {
setDialogTile('update')
//
const res = await NoticeApi.getNoticeApi(rowId)
unref(formRef)?.setValues(res)
}
//
const handleDetail = async (rowId: number) => {
setDialogTile('detail')
//
const res = await NoticeApi.getNoticeApi(rowId)
detailData.value = res
}
// /
const submitForm = async () => {
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
actionLoading.value = true
//
try {
const data = unref(formRef)?.formModel as NoticeApi.NoticeVO
if (actionType.value === 'create') {
await NoticeApi.createNoticeApi(data)
message.success(t('common.createSuccess'))
} else {
await NoticeApi.updateNoticeApi(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
} finally {
actionLoading.value = false
await reload()
}
}
})
}
</script>

View File

@ -1,103 +0,0 @@
<template>
<ContentWrap>
<div style="width: 100%; height: 500px">
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2 :columns="columns" :data="tableData" :width="width" :height="height" fixed />
</template>
</el-auto-resizer>
<el-pagination
:current-page="queryParms.pageNo"
:page-size="queryParms.pageSize"
layout="total, prev, pager, next"
:total="tableTotal"
@size-change="getList"
@current-change="getList"
/>
</div>
</ContentWrap>
</template>
<script setup lang="ts">
import { Column, TableV2FixedDir } from 'element-plus'
import * as NoticeApi from '@/api/system/notice'
import { XTextButton } from '@/components/XButton'
const { t } = useI18n() //
const columns: Column<any>[] = [
{
key: 'id',
dataKey: 'id', //{id:9527,name:'Mike'}id
title: 'id', //
width: 80, //
fixed: true //
},
{
key: 'title',
dataKey: 'title',
title: '公告标题',
width: 180
},
{
key: 'type',
dataKey: 'type',
title: '公告类型',
width: 180
},
{
key: 'status',
dataKey: 'status',
title: t('common.status'),
width: 180
},
{
key: 'content',
dataKey: 'content',
title: '公告内容',
width: 180
},
{
key: 'createTime',
dataKey: 'createTime',
title: t('common.createTime'),
width: 180
},
{
key: 'actionbtns',
dataKey: 'actionbtns', //{id:9527,name:'Mike'}id
title: '操作', //
width: 80, //
fixed: TableV2FixedDir.RIGHT, //
align: 'center',
cellRenderer: (date) =>
h(XTextButton, {
onClick: () => handleDelete(date.rowData),
type: 'danger',
preIcon: 'ep:delete',
title: t('action.del')
})
}
]
const tableData = ref([])
const tableTotal = ref(0)
const queryParms = reactive({
title: '',
status: undefined,
pageNo: 1,
pageSize: 10
})
const getList = async () => {
const res = await NoticeApi.getNoticePageApi(queryParms)
tableData.value = res.list
tableTotal.value = res.total
}
const handleDelete = (row) => {
console.info(row.id)
}
getList()
</script>

View File

@ -1,59 +0,0 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const rules = reactive({
title: [required],
type: [required]
})
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'seq',
action: true,
columns: [
{
title: '公告标题',
field: 'title',
isSearch: true
},
{
title: '公告类型',
field: 'type',
dictType: DICT_TYPE.SYSTEM_NOTICE_TYPE,
dictClass: 'number'
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: '公告内容',
field: 'content',
table: {
type: 'html'
},
form: {
component: 'Editor',
colProps: {
span: 24
},
componentProps: {
valueHtml: ''
}
},
isTable: false
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -22,6 +22,10 @@ const crudSchemas = reactive<VxeCrudSchema>({
primaryType: null, primaryType: null,
action: true, action: true,
columns: [ columns: [
{
title: '客户端端号',
field: 'clientId'
},
{ {
title: '客户端密钥', title: '客户端密钥',
field: 'secret' field: 'secret'

View File

@ -44,12 +44,13 @@ const [registerTable, { exportList }] = useXTable({
// //
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('edit') // const dialogTitle = ref(t('action.detail')) //
const actionType = ref('') // const actionType = ref('') //
// ========== ========== // ========== ==========
const detailData = ref() // Ref const detailData = ref() // Ref
const handleDetail = (row: SmsLoglApi.SmsLogVO) => { const handleDetail = (row: SmsLoglApi.SmsLogVO) => {
// //
actionType.value = 'detail'
detailData.value = row detailData.value = row
dialogVisible.value = true dialogVisible.value = true
} }

View File

@ -1,6 +1,9 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const authorizedGrantOptions = getStrDictOptions(DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE)
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
@ -25,9 +28,17 @@ const crudSchemas = reactive<VxeCrudSchema>({
{ {
title: '短信渠道', title: '短信渠道',
field: 'channelId', field: 'channelId',
dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE, // dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,
dictClass: 'number', // dictClass: 'number',
isSearch: true isSearch: true,
// table: {
// component: 'Select',
componentProps: {
options: authorizedGrantOptions
// multiple: false,
// filterable: true
}
// }
}, },
{ {
title: '发送状态', title: '发送状态',

View File

@ -1,6 +1,19 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
import * as smsApi from '@/api/system/sms/smsChannel'
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const tenantPackageOption = []
const getTenantPackageOptions = async () => {
const res = await smsApi.getSimpleSmsChannels()
console.log(res, 'resresres')
res.forEach((tenantPackage: TenantPackageVO) => {
tenantPackageOption.push({
key: tenantPackage.id,
value: tenantPackage.id,
label: tenantPackage.signature
})
})
}
getTenantPackageOptions()
// 表单校验 // 表单校验
export const rules = reactive({ export const rules = reactive({
type: [required], type: [required],
@ -20,6 +33,19 @@ const crudSchemas = reactive<VxeCrudSchema>({
action: true, action: true,
actionWidth: '280', actionWidth: '280',
columns: [ columns: [
{
title: '短信渠道编码',
field: 'channelId',
isSearch: false,
isForm: true,
isTable: false,
form: {
component: 'Select',
componentProps: {
options: tenantPackageOption
}
}
},
{ {
title: '模板编码', title: '模板编码',
field: 'code', field: 'code',

View File

@ -123,14 +123,37 @@ const setDialogTile = (type: string) => {
} }
// //
const handleCreate = () => { const handleCreate = async () => {
// //
setDialogTile('create') setDialogTile('create')
await nextTick()
console.log(allSchemas.formSchema, 'allSchemas.formSchema')
if (allSchemas.formSchema[4].field !== 'username') {
unref(formRef)?.addSchema(
{
field: 'username',
label: '用户名称',
component: 'Input'
},
0
)
unref(formRef)?.addSchema(
{
field: 'password',
label: '用户密码',
component: 'InputPassword'
},
1
)
}
} }
// //
const handleUpdate = async (rowId: number) => { const handleUpdate = async (rowId: number) => {
setDialogTile('update') setDialogTile('update')
await nextTick()
unref(formRef)?.delSchema('username')
unref(formRef)?.delSchema('password')
// //
const res = await TenantApi.getTenantApi(rowId) const res = await TenantApi.getTenantApi(rowId)
unref(formRef)?.setValues(res) unref(formRef)?.setValues(res)

View File

@ -19,12 +19,44 @@ const getTenantPackageOptions = async () => {
} }
getTenantPackageOptions() getTenantPackageOptions()
const validateName = (rule: any, value: any, callback: any) => {
const reg = /^[a-zA-Z0-9]{4,30}$/
if (value === '') {
callback(new Error('请输入用户名称'))
} else {
console.log(reg.test(rule), 'reg.test(rule)')
if (!reg.test(value)) {
callback(new Error('用户名称由 数字、字母 组成'))
} else {
callback()
}
}
}
const validateMobile = (rule: any, value: any, callback: any) => {
const reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
if (value === '') {
callback(new Error('请输入联系手机'))
} else {
if (!reg.test(value)) {
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
}
// 表单校验 // 表单校验
export const rules = reactive({ export const rules = reactive({
name: [required], name: [required],
packageId: [required], packageId: [required],
contactName: [required], contactName: [required],
contactMobile: [required], contactMobile: [
required,
{
validator: validateMobile,
trigger: 'blur'
}
],
accountCount: [required], accountCount: [required],
expireTime: [required], expireTime: [required],
username: [ username: [
@ -34,7 +66,8 @@ export const rules = reactive({
max: 30, max: 30,
trigger: 'blur', trigger: 'blur',
message: '用户名称长度为 4-30 个字符' message: '用户名称长度为 4-30 个字符'
} },
{ validator: validateName, trigger: 'blur' }
], ],
password: [ password: [
required, required,

View File

@ -15,7 +15,6 @@
<XTextButton preIcon="ep:delete" :title="t('action.del')" @click="deleteData(row.id)" /> <XTextButton preIcon="ep:delete" :title="t('action.del')" @click="deleteData(row.id)" />
</template> </template>
</XTable> </XTable>
</ContentWrap>
<XModal v-model="dialogVisible" :title="dialogTitle"> <XModal v-model="dialogVisible" :title="dialogTitle">
<!-- 对话框(添加 / 修改) --> <!-- 对话框(添加 / 修改) -->
<Form <Form
@ -25,7 +24,7 @@
ref="formRef" ref="formRef"
> >
<template #menuIds> <template #menuIds>
<el-card> <el-card class="cardHeight">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
全选/全不选: 全选/全不选:
@ -44,7 +43,7 @@
show-checkbox show-checkbox
:props="defaultProps" :props="defaultProps"
:data="menuOptions" :data="menuOptions"
empty-text="加载中,请稍" empty-text="加载中,请稍"
/> />
</el-card> </el-card>
</template> </template>
@ -63,6 +62,7 @@
<XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" /> <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />
</template> </template>
</XModal> </XModal>
</ContentWrap>
</template> </template>
<script setup lang="ts" name="TenantPackage"> <script setup lang="ts" name="TenantPackage">
import { handleTree, defaultProps } from '@/utils/tree' import { handleTree, defaultProps } from '@/utils/tree'
@ -179,7 +179,7 @@ onMounted(async () => {
// getList() // getList()
</script> </script>
<style scoped> <style scoped>
.el-card { .cardHeight {
width: 100%; width: 100%;
max-height: 400px; max-height: 400px;
overflow-y: scroll; overflow-y: scroll;

View File

@ -1,6 +1,18 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
// 国际化 // 国际化
const { t } = useI18n() const { t } = useI18n()
const validateMobile = (rule: any, value: any, callback: any) => {
const reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
if (value === '') {
callback(new Error('请输入联系手机'))
} else {
if (!reg.test(value)) {
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
}
// 表单校验 // 表单校验
export const rules = reactive({ export const rules = reactive({
username: [required], username: [required],
@ -17,12 +29,13 @@ export const rules = reactive({
], ],
status: [required], status: [required],
mobile: [ mobile: [
required,
{ {
required: true,
len: 11, len: 11,
trigger: 'blur', trigger: 'blur',
message: '请输入正确的手机号码' message: '请输入正确的手机号码'
} },
{ validator: validateMobile, trigger: 'blur' }
] ]
}) })
// crudSchemas // crudSchemas
@ -47,6 +60,13 @@ const crudSchemas = reactive<VxeCrudSchema>({
component: 'InputPassword' component: 'InputPassword'
} }
}, },
{
title: '用户' + t('profile.user.sex'),
field: 'sex',
dictType: DICT_TYPE.SYSTEM_USER_SEX,
dictClass: 'number',
table: { show: false }
},
{ {
title: '用户昵称', title: '用户昵称',
field: 'nickname' field: 'nickname'