Commit 2a3fe7d2 by 芋道源码 Committed by Gitee

!45 重构:短信模板和短信日志vue2改vue3

Merge pull request !45 from puhui999/master
parents 44819641 c735cd72
...@@ -5,4 +5,5 @@ dist-ssr ...@@ -5,4 +5,5 @@ dist-ssr
*.local *.local
/dist* /dist*
*-lock.* *-lock.*
pnpm-debug pnpm-debug
\ No newline at end of file .idea
...@@ -24,41 +24,41 @@ export interface SensitiveWordExportReqVO { ...@@ -24,41 +24,41 @@ export interface SensitiveWordExportReqVO {
} }
// 查询敏感词列表 // 查询敏感词列表
export const getSensitiveWordPageApi = (params: SensitiveWordPageReqVO) => { export const getSensitiveWordPage = (params: SensitiveWordPageReqVO) => {
return request.get({ url: '/system/sensitive-word/page', params }) return request.get({ url: '/system/sensitive-word/page', params })
} }
// 查询敏感词详情 // 查询敏感词详情
export const getSensitiveWordApi = (id: number) => { export const getSensitiveWord = (id: number) => {
return request.get({ url: '/system/sensitive-word/get?id=' + id }) return request.get({ url: '/system/sensitive-word/get?id=' + id })
} }
// 新增敏感词 // 新增敏感词
export const createSensitiveWordApi = (data: SensitiveWordVO) => { export const createSensitiveWord = (data: SensitiveWordVO) => {
return request.post({ url: '/system/sensitive-word/create', data }) return request.post({ url: '/system/sensitive-word/create', data })
} }
// 修改敏感词 // 修改敏感词
export const updateSensitiveWordApi = (data: SensitiveWordVO) => { export const updateSensitiveWord = (data: SensitiveWordVO) => {
return request.put({ url: '/system/sensitive-word/update', data }) return request.put({ url: '/system/sensitive-word/update', data })
} }
// 删除敏感词 // 删除敏感词
export const deleteSensitiveWordApi = (id: number) => { export const deleteSensitiveWord = (id: number) => {
return request.delete({ url: '/system/sensitive-word/delete?id=' + id }) return request.delete({ url: '/system/sensitive-word/delete?id=' + id })
} }
// 导出敏感词 // 导出敏感词
export const exportSensitiveWordApi = (params: SensitiveWordExportReqVO) => { export const exportSensitiveWord = (params: SensitiveWordExportReqVO) => {
return request.download({ url: '/system/sensitive-word/export-excel', params }) return request.download({ url: '/system/sensitive-word/export-excel', params })
} }
// 获取所有敏感词的标签数组 // 获取所有敏感词的标签数组
export const getSensitiveWordTagsApi = () => { export const getSensitiveWordTags = () => {
return request.get({ url: '/system/sensitive-word/get-tags' }) return request.get({ url: '/system/sensitive-word/get-tags' })
} }
// 获得文本所包含的不合法的敏感词数组 // 获得文本所包含的不合法的敏感词数组
export const validateTextApi = (id: number) => { export const validateText = (id: number) => {
return request.get({ url: '/system/sensitive-word/validate-text?' + id }) return request.get({ url: '/system/sensitive-word/validate-text?' + id })
} }
...@@ -12,6 +12,12 @@ export interface SmsChannelVO { ...@@ -12,6 +12,12 @@ export interface SmsChannelVO {
createTime: Date createTime: Date
} }
export interface SmsChannelListVO {
id: number
code: string
signature: string
}
export interface SmsChannelPageReqVO extends PageParam { export interface SmsChannelPageReqVO extends PageParam {
signature?: string signature?: string
code?: string code?: string
......
import request from '@/config/axios' import request from '@/config/axios'
export interface SmsLogVO { export interface SmsLogVO {
id: number id: number | null
channelId: number channelId: number | null
channelCode: string channelCode: string
templateId: number templateId: number | null
templateCode: string templateCode: string
templateType: number templateType: number | null
templateContent: string templateContent: string
templateParams: Map<string, object> templateParams: Map<string, object> | null
apiTemplateId: string
mobile: string mobile: string
userId: number userId: number | null
userType: number userType: number | null
sendStatus: number sendStatus: number | null
sendTime: Date sendTime: Date | null
sendCode: number sendCode: number | null
sendMsg: string sendMsg: string
apiSendCode: string apiSendCode: string
apiSendMsg: string apiSendMsg: string
apiRequestId: string apiRequestId: string
apiSerialNo: string apiSerialNo: string
receiveStatus: number receiveStatus: number | null
receiveTime: Date receiveTime: Date | null
apiReceiveCode: string apiReceiveCode: string
apiReceiveMsg: string apiReceiveMsg: string
createTime: Date createTime: Date | null
} }
export interface SmsLogPageReqVO extends PageParam { export interface SmsLogPageReqVO extends PageParam {
channelId?: number channelId?: number | null
templateId?: number templateId?: number | null
mobile?: string mobile?: string
sendStatus?: number sendStatus?: number | null
sendTime?: Date[] sendTime?: Date[]
receiveStatus?: number receiveStatus?: number | null
receiveTime?: Date[] receiveTime?: Date[]
} }
export interface SmsLogExportReqVO { export interface SmsLogExportReqVO {
......
import request from '@/config/axios' import request from '@/config/axios'
export interface SmsTemplateVO { export interface SmsTemplateVO {
id: number id: number | null
type: number type: number | null
status: number status: number | null
code: string code: string
name: string name: string
content: string content: string
remark: string remark: string
apiTemplateId: string apiTemplateId: string
channelId: number channelId: number | null
channelCode: string channelCode?: string
params: string[] params?: string[]
createTime: Date createTime?: Date
} }
export interface SendSmsReqVO { export interface SendSmsReqVO {
...@@ -21,13 +21,13 @@ export interface SendSmsReqVO { ...@@ -21,13 +21,13 @@ export interface SendSmsReqVO {
templateParams: Map<String, Object> templateParams: Map<String, Object>
} }
export interface SmsTemplatePageReqVO { export interface SmsTemplatePageReqVO extends PageParam {
type?: number type?: number | null
status?: number status?: number | null
code?: string code?: string
content?: string content?: string
apiTemplateId?: string apiTemplateId?: string
channelId?: number channelId?: number | null
createTime?: Date[] createTime?: Date[]
} }
......
import RightToolbar from './src/index.vue'
export interface columnsType {
key?: number
label?: string
visible?: boolean
}
export { RightToolbar }
<template>
<div :style="style">
<el-row justify="end">
<el-tooltip
class="item"
effect="dark"
:content="showSearch ? '隐藏搜索' : '显示搜索'"
placement="top"
v-if="search"
>
<el-button circle @click="toggleSearch()">
<Icon icon="ep:search" />
</el-button>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button circle @click="refresh()">
<Icon icon="ep:refresh" />
</el-button>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="isColumns">
<el-button circle @click="showColumn()">
<Icon icon="ep:menu" />
</el-button>
</el-tooltip>
</el-row>
<el-dialog :title="title" v-model="open" append-to-body>
<el-transfer
:titles="['显示', '隐藏']"
v-model="value"
:data="columns"
@change="dataChange"
/>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="RightToolbar">
import type { CSSProperties } from 'vue'
import type { columnsType } from '@/components/RightToolbar'
import { propTypes } from '@/utils/propTypes'
// 显隐数据
const value = ref<number[]>([])
// 弹出层标题
const title = ref('显示/隐藏')
// 是否显示弹出层
const open = ref(false)
const props = defineProps({
showSearch: propTypes.bool.def(true),
columns: {
type: Array as PropType<columnsType[]>,
default: () => []
},
search: propTypes.bool.def(true),
gutter: propTypes.number.def(10)
})
const isColumns = computed(() => props.columns?.length > 0)
const style = computed((): CSSProperties => {
const ret: CSSProperties = {}
if (props.gutter) {
ret.marginRight = `${props.gutter / 2}px`
}
return ret
})
const emit = defineEmits(['update:showSearch', 'queryTable'])
// 搜索
const toggleSearch = () => {
emit('update:showSearch', !props.showSearch)
}
// 刷新
const refresh = () => {
emit('queryTable')
}
// 右侧列表元素变化
const dataChange = (data: number[]) => {
props.columns.forEach((item) => {
const key: number = item.key!
item.visible = !data.includes(key)
})
}
// 打开显隐列dialog
const showColumn = () => {
open.value = true
}
// 显隐列初始默认隐藏列
const init = () => {
props.columns.forEach((item, index) => {
if (item.visible === false) {
value.value.push(index)
}
})
}
init()
</script>
<style lang="scss" scoped>
:deep(.el-transfer__button) {
border-radius: 50%;
padding: 12px;
display: block;
margin-left: 0px;
}
:deep(.el-transfer__button:first-child) {
margin-bottom: 10px;
}
</style>
...@@ -9,6 +9,7 @@ import { XButton, XTextButton } from '@/components/XButton' ...@@ -9,6 +9,7 @@ import { XButton, XTextButton } from '@/components/XButton'
import { DictTag } from '@/components/DictTag' import { DictTag } from '@/components/DictTag'
import { ContentWrap } from '@/components/ContentWrap' import { ContentWrap } from '@/components/ContentWrap'
import { Descriptions } from '@/components/Descriptions' import { Descriptions } from '@/components/Descriptions'
import { RightToolbar } from '@/components/RightToolbar'
export const setupGlobCom = (app: App<Element>): void => { export const setupGlobCom = (app: App<Element>): void => {
app.component('Icon', Icon) app.component('Icon', Icon)
...@@ -22,4 +23,5 @@ export const setupGlobCom = (app: App<Element>): void => { ...@@ -22,4 +23,5 @@ export const setupGlobCom = (app: App<Element>): void => {
app.component('DictTag', DictTag) app.component('DictTag', DictTag)
app.component('ContentWrap', ContentWrap) app.component('ContentWrap', ContentWrap)
app.component('Descriptions', Descriptions) app.component('Descriptions', Descriptions)
app.component('RightToolbar', RightToolbar)
} }
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs' import { parseTime } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message' import * as NotifyMessageApi from '@/api/system/notify/message'
const { push } = useRouter() const { push } = useRouter()
...@@ -57,7 +57,7 @@ onMounted(() => { ...@@ -57,7 +57,7 @@ onMounted(() => {
{{ item.templateNickname }}{{ item.templateContent }} {{ item.templateNickname }}{{ item.templateContent }}
</span> </span>
<span class="message-date"> <span class="message-date">
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }} {{ parseTime(item.createTime) }}
</span> </span>
</div> </div>
</div> </div>
......
...@@ -303,7 +303,14 @@ export default { ...@@ -303,7 +303,14 @@ export default {
dialog: { dialog: {
dialog: '弹窗', dialog: '弹窗',
open: '打开', open: '打开',
close: '关闭' close: '关闭',
sms: {
template: {
addTitle: '添加短信模板',
updtaeTitle: '修改短信模板',
sendSms: '发送短信'
}
}
}, },
sys: { sys: {
api: { api: {
......
/* eslint-disable */ // generated by unplugin-vue-components
/* prettier-ignore */ // We suggest you to commit this file into source control
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core' import '@vue/runtime-core'
...@@ -23,7 +21,6 @@ declare module '@vue/runtime-core' { ...@@ -23,7 +21,6 @@ declare module '@vue/runtime-core' {
DictTag: typeof import('./../components/DictTag/src/DictTag.vue')['default'] DictTag: typeof import('./../components/DictTag/src/DictTag.vue')['default']
Echart: typeof import('./../components/Echart/src/Echart.vue')['default'] Echart: typeof import('./../components/Echart/src/Echart.vue')['default']
Editor: typeof import('./../components/Editor/src/Editor.vue')['default'] Editor: typeof import('./../components/Editor/src/Editor.vue')['default']
ElAutoResizer: typeof import('element-plus/es')['ElAutoResizer']
ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBadge: typeof import('element-plus/es')['ElBadge'] ElBadge: typeof import('element-plus/es')['ElBadge']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
...@@ -55,7 +52,6 @@ declare module '@vue/runtime-core' { ...@@ -55,7 +52,6 @@ declare module '@vue/runtime-core' {
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
...@@ -78,8 +74,6 @@ declare module '@vue/runtime-core' { ...@@ -78,8 +74,6 @@ declare module '@vue/runtime-core' {
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTransfer: typeof import('element-plus/es')['ElTransfer'] ElTransfer: typeof import('element-plus/es')['ElTransfer']
ElTree: typeof import('element-plus/es')['ElTree'] ElTree: typeof import('element-plus/es')['ElTree']
...@@ -107,6 +101,7 @@ declare module '@vue/runtime-core' { ...@@ -107,6 +101,7 @@ declare module '@vue/runtime-core' {
ScriptTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ScriptTask.vue')['default'] ScriptTask: typeof import('./../components/bpmnProcessDesigner/package/penal/task/task-components/ScriptTask.vue')['default']
Search: typeof import('./../components/Search/src/Search.vue')['default'] Search: typeof import('./../components/Search/src/Search.vue')['default']
SignalAndMessage: typeof import('./../components/bpmnProcessDesigner/package/penal/signal-message/SignalAndMessage.vue')['default'] SignalAndMessage: typeof import('./../components/bpmnProcessDesigner/package/penal/signal-message/SignalAndMessage.vue')['default']
Src: typeof import('./../components/RightToolbar/src/index.vue')['default']
Sticky: typeof import('./../components/Sticky/src/Sticky.vue')['default'] Sticky: typeof import('./../components/Sticky/src/Sticky.vue')['default']
Table: typeof import('./../components/Table/src/Table.vue')['default'] Table: typeof import('./../components/Table/src/Table.vue')['default']
Tooltip: typeof import('./../components/Tooltip/src/Tooltip.vue')['default'] Tooltip: typeof import('./../components/Tooltip/src/Tooltip.vue')['default']
......
...@@ -72,5 +72,5 @@ declare global { ...@@ -72,5 +72,5 @@ declare global {
// for type re-export // for type re-export
declare global { declare global {
// @ts-ignore // @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue' export type { Component,ComponentPublicInstance,ComputedRef,InjectionKey,PropType,Ref,VNode } from 'vue'
} }
...@@ -69,7 +69,16 @@ export const getDictObj = (dictType: string, value: any) => { ...@@ -69,7 +69,16 @@ export const getDictObj = (dictType: string, value: any) => {
} }
}) })
} }
export const getDictLabel = (dictType: string, value: any) => {
const dictOptions: DictDataType[] = getDictOptions(dictType)
const dictLabel = ref('')
dictOptions.forEach((dict: DictDataType) => {
if (dict.value === value) {
dictLabel.value = dict.label
}
})
return dictLabel.value
}
export enum DICT_TYPE { export enum DICT_TYPE {
USER_TYPE = 'user_type', USER_TYPE = 'user_type',
COMMON_STATUS = 'common_status', COMMON_STATUS = 'common_status',
......
...@@ -14,6 +14,51 @@ import dayjs from 'dayjs' ...@@ -14,6 +14,51 @@ import dayjs from 'dayjs'
export function formatDate(date: Date, format: string): string { export function formatDate(date: Date, format: string): string {
return dayjs(date).format(format) return dayjs(date).format(format)
} }
// 日期格式化
export function parseTime(time: any, pattern?: string) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time
.replace(new RegExp(/-/gm), '/')
.replace('T', ' ')
.replace(new RegExp(/\.\d{3}/gm), '')
}
if (typeof time === 'number' && time.toString().length === 10) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') {
return ['日', '一', '二', '三', '四', '五', '六'][value]
}
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
/** /**
* 获取当前日期是第几周 * 获取当前日期是第几周
......
...@@ -34,13 +34,13 @@ ...@@ -34,13 +34,13 @@
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<Icon icon="ep:calendar" class="mr-5px" />{{ t('profile.user.createTime') }} <Icon icon="ep:calendar" class="mr-5px" />{{ t('profile.user.createTime') }}
<div class="pull-right">{{ dayjs(userInfo?.createTime).format('YYYY-MM-DD') }}</div> <div class="pull-right">{{ parseTime(userInfo?.createTime) }}</div>
</li> </li>
</ul> </ul>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs' import { parseTime } from '@/utils/formatTime'
import UserAvatar from './UserAvatar.vue' import UserAvatar from './UserAvatar.vue'
import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile' import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile'
......
...@@ -112,13 +112,13 @@ ...@@ -112,13 +112,13 @@
</label> </label>
<label style="font-weight: normal" v-if="item.createTime">创建时间:</label> <label style="font-weight: normal" v-if="item.createTime">创建时间:</label>
<label style="color: #8a909c; font-weight: normal"> <label style="color: #8a909c; font-weight: normal">
{{ dayjs(item?.createTime).format('YYYY-MM-DD HH:mm:ss') }} {{ parseTime(item?.createTime) }}
</label> </label>
<label v-if="item.endTime" style="margin-left: 30px; font-weight: normal"> <label v-if="item.endTime" style="margin-left: 30px; font-weight: normal">
审批时间: 审批时间:
</label> </label>
<label v-if="item.endTime" style="color: #8a909c; font-weight: normal"> <label v-if="item.endTime" style="color: #8a909c; font-weight: normal">
{{ dayjs(item?.endTime).format('YYYY-MM-DD HH:mm:ss') }} {{ parseTime(item?.endTime) }}
</label> </label>
<label v-if="item.durationInMillis" style="margin-left: 30px; font-weight: normal"> <label v-if="item.durationInMillis" style="margin-left: 30px; font-weight: normal">
耗时: 耗时:
...@@ -192,7 +192,7 @@ ...@@ -192,7 +192,7 @@
</ContentWrap> </ContentWrap>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs' import { parseTime } from '@/utils/formatTime'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import * as DefinitionApi from '@/api/bpm/definition' import * as DefinitionApi from '@/api/bpm/definition'
......
...@@ -12,11 +12,7 @@ ...@@ -12,11 +12,7 @@
/> />
</template> </template>
<template #beginTime_default="{ row }"> <template #beginTime_default="{ row }">
<span>{{ <span>{{ parseTime(row.beginTime) + ' ~ ' + parseTime(row.endTime) }}</span>
dayjs(row.beginTime).format('YYYY-MM-DD HH:mm:ss') +
' ~ ' +
dayjs(row.endTime).format('YYYY-MM-DD HH:mm:ss')
}}</span>
</template> </template>
<template #duration_default="{ row }"> <template #duration_default="{ row }">
<span>{{ row.duration + ' 毫秒' }}</span> <span>{{ row.duration + ' 毫秒' }}</span>
...@@ -48,7 +44,7 @@ ...@@ -48,7 +44,7 @@
</XModal> </XModal>
</template> </template>
<script setup lang="ts" name="JobLog"> <script setup lang="ts" name="JobLog">
import dayjs from 'dayjs' import { parseTime } from '@/utils/formatTime'
import * as JobLogApi from '@/api/infra/jobLog' import * as JobLogApi from '@/api/infra/jobLog'
import { allSchemas } from './jobLog.data' import { allSchemas } from './jobLog.data'
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
<li v-for="item in getList" class="mt-2" :key="item.time"> <li v-for="item in getList" class="mt-2" :key="item.time">
<div class="flex items-center"> <div class="flex items-center">
<span class="mr-2 text-primary font-medium">收到消息:</span> <span class="mr-2 text-primary font-medium">收到消息:</span>
<span>{{ dayjs(item.time).format('YYYY-MM-DD HH:mm:ss') }}</span> <span>{{ parseTime(item.time) }}</span>
</div> </div>
<div> <div>
{{ item.res }} {{ item.res }}
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs' import { parseTime } from '@/utils/formatTime'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
import { useWebSocket } from '@vueuse/core' import { useWebSocket } from '@vueuse/core'
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
</template> </template>
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts" name="SensitiveWordForm">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as SensitiveWordApi from '@/api/system/sensitiveWord' import * as SensitiveWordApi from '@/api/system/sensitiveWord'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
...@@ -81,7 +81,7 @@ const openModal = async (type: string, id?: number) => { ...@@ -81,7 +81,7 @@ const openModal = async (type: string, id?: number) => {
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await SensitiveWordApi.getSensitiveWordApi(id) formData.value = await SensitiveWordApi.getSensitiveWord(id)
console.log(formData.value) console.log(formData.value)
} finally { } finally {
formLoading.value = false formLoading.value = false
...@@ -102,10 +102,10 @@ const submitForm = async () => { ...@@ -102,10 +102,10 @@ const submitForm = async () => {
try { try {
const data = formData.value as unknown as SensitiveWordApi.SensitiveWordVO const data = formData.value as unknown as SensitiveWordApi.SensitiveWordVO
if (formType.value === 'create') { if (formType.value === 'create') {
await SensitiveWordApi.createSensitiveWordApi(data) // TODO @blue-syd:去掉 API 后缀 await SensitiveWordApi.createSensitiveWord(data) // TODO @blue-syd:去掉 API 后缀
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
await SensitiveWordApi.updateSensitiveWordApi(data) // TODO @blue-syd:去掉 API 后缀 await SensitiveWordApi.updateSensitiveWord(data) // TODO @blue-syd:去掉 API 后缀
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
} }
modelVisible.value = false modelVisible.value = false
......
...@@ -126,14 +126,14 @@ ...@@ -126,14 +126,14 @@
</content-wrap> </content-wrap>
<!-- 表单弹窗:添加/修改 --> <!-- 表单弹窗:添加/修改 -->
<config-form ref="modalRef" @success="getList" /> <SensitiveWordForm ref="modalRef" @success="getList" />
</template> </template>
<script setup lang="ts" name="SensitiveWord"> <script setup lang="ts" name="SensitiveWord">
import { DICT_TYPE, getDictOptions } from '@/utils/dict' import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import * as SensitiveWordApi from '@/api/system/sensitiveWord' import * as SensitiveWordApi from '@/api/system/sensitiveWord'
import ConfigForm from './form.vue' // TODO @blue-syd:组件名不对 import SensitiveWordForm from './form.vue' // TODO @blue-syd:组件名不对
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
...@@ -156,7 +156,7 @@ const tags = ref([]) ...@@ -156,7 +156,7 @@ const tags = ref([])
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
const data = await SensitiveWordApi.getSensitiveWordPageApi(queryParams) // TODO @blue-syd:去掉 API 后缀哈 const data = await SensitiveWordApi.getSensitiveWordPage(queryParams) // TODO @blue-syd:去掉 API 后缀哈
list.value = data.list list.value = data.list
total.value = data.total total.value = data.total
} finally { } finally {
...@@ -190,7 +190,7 @@ const handleDelete = async (id: number) => { ...@@ -190,7 +190,7 @@ const handleDelete = async (id: number) => {
// 删除的二次确认 // 删除的二次确认
await message.delConfirm() await message.delConfirm()
// 发起删除 // 发起删除
await SensitiveWordApi.deleteSensitiveWordApi(id) await SensitiveWordApi.deleteSensitiveWord(id)
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// 刷新列表 // 刷新列表
await getList() await getList()
...@@ -204,7 +204,7 @@ const handleExport = async () => { ...@@ -204,7 +204,7 @@ const handleExport = async () => {
await message.exportConfirm() await message.exportConfirm()
// 发起导出 // 发起导出
exportLoading.value = true exportLoading.value = true
const data = await SensitiveWordApi.exportSensitiveWordApi(queryParams) // TODO @blue-syd:去掉 API 后缀哈 const data = await SensitiveWordApi.exportSensitiveWord(queryParams) // TODO @blue-syd:去掉 API 后缀哈
download.excel(data, '敏感词.xls') download.excel(data, '敏感词.xls')
} catch { } catch {
} finally { } finally {
...@@ -214,7 +214,7 @@ const handleExport = async () => { ...@@ -214,7 +214,7 @@ const handleExport = async () => {
/** 获得 Tag 标签列表 */ /** 获得 Tag 标签列表 */
const getTags = async () => { const getTags = async () => {
tags.value = await SensitiveWordApi.getSensitiveWordTagsApi() // TODO @blue-syd:去掉 API 后缀哈 tags.value = await SensitiveWordApi.getSensitiveWordTags() // TODO @blue-syd:去掉 API 后缀哈
} }
/** 初始化 **/ /** 初始化 **/
......
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
const { t } = useI18n() // 国际化
const authorizedGrantOptions = getStrDictOptions(DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE)
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '日志编号',
action: true,
columns: [
{
title: '手机号',
field: 'mobile',
isSearch: true
},
{
title: '短信内容',
field: 'templateContent'
},
{
title: '模板编号',
field: 'templateId',
isSearch: true
},
{
title: '短信渠道',
field: 'channelId',
// dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,
// dictClass: 'number',
isSearch: true,
// table: {
// component: 'Select',
componentProps: {
options: authorizedGrantOptions
// multiple: false,
// filterable: true
}
// }
},
{
title: '发送状态',
field: 'sendStatus',
dictType: DICT_TYPE.SYSTEM_SMS_SEND_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: '发送时间',
field: 'sendTime',
formatter: 'formatDate',
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: '短信类型',
field: 'templateType',
dictType: DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE,
dictClass: 'number',
isSearch: true
},
{
title: '接收状态',
field: 'receiveStatus',
dictType: DICT_TYPE.SYSTEM_SMS_RECEIVE_STATUS,
dictClass: 'number',
isSearch: true
},
{
title: '接收时间',
field: 'receiveTime',
formatter: 'formatDate',
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate'
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
<template>
<Dialog :title="modelTitle" v-model="modelVisible">
<!-- 修改/新增 -->
<el-form
v-if="['template.addTitle', 'template.updtaeTitle'].includes(formType)"
ref="formRef"
:model="formData"
:rules="formRules"
label-width="140px"
>
<el-form-item label="短信渠道编号" prop="channelId">
<el-select v-model="formData.channelId" placeholder="请选择短信渠道编号">
<el-option
v-for="channel in channelOptions"
:key="channel.id"
:value="channel.id"
:label="
channel.signature + optionLabel(DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE, channel.code)
"
/>
</el-select>
</el-form-item>
<el-form-item label="短信类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择短信类型">
<el-option
v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="模板编号" prop="code">
<el-input v-model="formData.code" placeholder="请输入模板编号" />
</el-form-item>
<el-form-item label="模板名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入模板名称" />
</el-form-item>
<el-form-item label="模板内容" prop="content">
<el-input type="textarea" v-model="formData.content" placeholder="请输入模板内容" />
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="parseInt(dict.value)"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item label="短信 API 模板编号" prop="apiTemplateId">
<el-input v-model="formData.apiTemplateId" placeholder="请输入短信 API 的模板编号" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<!-- 短信测试 -->
<el-form
v-if="formType === 'template.sendSms'"
ref="sendSmsFormRef"
:model="sendSmsForm"
:rules="sendSmsRules"
>
<el-form-item label="模板内容" prop="content">
<el-input
v-model="sendSmsForm.content"
type="textarea"
placeholder="请输入模板内容"
readonly
/>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="sendSmsForm.mobile" placeholder="请输入手机号" />
</el-form-item>
<el-form-item
v-for="param in sendSmsForm.params"
:key="param"
:label="'参数 {' + param + '}'"
:prop="'templateParams.' + param"
>
<el-input
v-model="sendSmsForm.templateParams[param]"
:placeholder="'请输入 ' + param + ' 参数'"
/>
</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" name="SmsTemplateFrom">
import { DICT_TYPE, getDictOptions, getDictLabel } from '@/utils/dict'
import * as templateApi from '@/api/system/sms/smsTemplate'
import * as SmsChannelApi from '@/api/system/sms/smsChannel'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
defineProps({
channelOptions: {
type: Array as PropType<SmsChannelApi.SmsChannelListVO[]>,
define: () => {}
}
})
const modelVisible = ref(false) // 弹窗的是否展示
const modelTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const formType = ref('') // 表单的类型
const formData = ref<templateApi.SmsTemplateVO>({
id: null,
type: null,
status: null,
code: '',
name: '',
content: '',
remark: '',
apiTemplateId: '',
channelId: null
})
const formRules = reactive({
type: [{ required: true, message: '短信类型不能为空', trigger: 'change' }],
status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }],
code: [{ required: true, message: '模板编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '模板名称不能为空', trigger: 'blur' }],
content: [{ required: true, message: '模板内容不能为空', trigger: 'blur' }],
apiTemplateId: [{ required: true, message: '短信 API 的模板编号不能为空', trigger: 'blur' }],
channelId: [{ required: true, message: '短信渠道编号不能为空', trigger: 'change' }]
})
const formRef = ref() // 表单 Ref
const optionLabel = computed(
() => (type: string, code: string) => `【${getDictLabel(type, code)}】`
)
// 发送短信表单相关
const sendSmsForm = ref({
content: '',
params: {},
mobile: '',
templateCode: '',
templateParams: {}
})
const sendSmsRules = reactive({
mobile: [{ required: true, message: '手机不能为空', trigger: 'blur' }],
templateCode: [{ required: true, message: '模版编码不能为空', trigger: 'blur' }],
templateParams: {}
})
const sendSmsFormRef = ref()
/** 打开弹窗 */
interface openModalOption {
type: string
// 编辑传id
id?: ''
// 短信测试传row
row?: any
}
const openModal = async (option: openModalOption) => {
modelVisible.value = true
modelTitle.value = t('dialog.sms.' + option.type)
formType.value = option.type
resetForm()
resetSendSms()
// 短信测试
if (option.row) {
sendSmsForm.value.content = option.row.content
sendSmsForm.value.params = option.row.params
sendSmsForm.value.templateCode = option.row.code
sendSmsForm.value.templateParams = option.row.params.reduce(function (obj, item) {
obj[item] = undefined
return obj
}, {})
sendSmsRules.templateParams = option.row.params.reduce(function (obj, item) {
obj[item] = { required: true, message: '参数 ' + item + ' 不能为空', trigger: 'change' }
return obj
}, {})
}
// 修改时,设置数据
if (option.id) {
formLoading.value = true
try {
formData.value = await templateApi.getSmsTemplateApi(option.id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
/** 提交表单 */
const submitForm = async () => {
formLoading.value = true
// 提交请求
if (['template.addTitle', 'template.updtaeTitle'].includes(formType.value)) {
// 校验表单
if (!formRef) return
const valid = await formRef.value.validate()
if (!valid) return
try {
const data = formData.value as templateApi.SmsTemplateVO
if (formType.value === 'template.addTitle') {
await templateApi.createSmsTemplateApi(data)
message.success(t('common.createSuccess'))
} else {
await templateApi.updateSmsTemplateApi(data)
message.success(t('common.updateSuccess'))
}
modelVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
if (formType.value === 'template.sendSms') {
sendSmsTest()
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: null,
type: null,
status: null,
code: '',
name: '',
content: '',
remark: '',
apiTemplateId: '',
channelId: null
}
formRef.value?.resetFields()
}
/** 重置发送短信的表单 */
const resetSendSms = () => {
// 根据 row 重置表单
sendSmsForm.value = {
content: '',
params: {},
mobile: '',
templateCode: '',
templateParams: {}
}
sendSmsFormRef.value?.resetFields()
}
/** 发送短信 */
const sendSmsTest = async () => {
const data: templateApi.SendSmsReqVO = {
mobile: sendSmsForm.value.mobile,
templateCode: sendSmsForm.value.templateCode,
templateParams: sendSmsForm.value.templateParams as unknown as Map<string, Object>
}
const res = await templateApi.sendSmsApi(data)
if (res) {
message.success('提交发送成功!发送结果,见发送日志编号:' + res)
}
formLoading.value = false
modelVisible.value = false
}
</script>
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
import * as smsApi from '@/api/system/sms/smsChannel'
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({
type: [required],
status: [required],
code: [required],
name: [required],
content: [required],
apiTemplateId: [required],
channelId: [required]
})
// CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id',
primaryType: 'id',
primaryTitle: '模板编号',
action: true,
actionWidth: '280',
columns: [
{
title: '短信渠道编码',
field: 'channelId',
isSearch: false,
isForm: true,
isTable: false,
form: {
component: 'Select',
componentProps: {
options: tenantPackageOption
}
}
},
{
title: '模板编码',
field: 'code',
isSearch: true
},
{
title: '模板名称',
field: 'name',
isSearch: true
},
{
title: '模板内容',
field: 'content'
},
{
title: '短信 API 的模板编号',
field: 'apiTemplateId',
isSearch: true
},
{
title: '短信类型',
field: 'type',
dictType: DICT_TYPE.SYSTEM_SMS_TEMPLATE_TYPE,
dictClass: 'number',
isSearch: true,
table: {
width: 80
}
},
{
title: t('common.status'),
field: 'status',
dictType: DICT_TYPE.COMMON_STATUS,
dictClass: 'number',
isSearch: true,
table: {
width: 80
}
},
{
title: t('form.remark'),
field: 'remark',
isTable: false
},
{
title: t('common.createTime'),
field: 'createTime',
formatter: 'formatDate',
isForm: false,
search: {
show: true,
itemRender: {
name: 'XDataTimePicker'
}
}
}
]
})
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
"vite-plugin-svg-icons/client", "vite-plugin-svg-icons/client",
"@form-create/element-ui/types" "@form-create/element-ui/types"
], ],
"outDir": "target", // 请保留这个属性,防止tsconfig.json文件报错
"typeRoots": ["./node_modules/@types/", "./types"] "typeRoots": ["./node_modules/@types/", "./types"]
}, },
"include": [ "include": [
...@@ -40,5 +41,5 @@ ...@@ -40,5 +41,5 @@
"src/types/auto-imports.d.ts", "src/types/auto-imports.d.ts",
"src/types/auto-components.d.ts" "src/types/auto-components.d.ts"
], ],
"exclude": ["dist", "node_modules"] "exclude": ["dist", "target", "node_modules"]
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment