Merge remote-tracking branch 'yudao/dev' into dev-to-dev

This commit is contained in:
puhui999
2023-05-20 12:06:00 +08:00
26 changed files with 773 additions and 267 deletions

View File

@ -87,7 +87,7 @@
<MyProcessViewer
key="designer"
v-model="bpmnXML"
:value="bpmnXML"
:value="bpmnXML as any"
v-bind="bpmnControlForm"
:prefix="bpmnControlForm.prefix"
/>

View File

@ -68,7 +68,7 @@ const formRules = reactive({
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
const userList = ref([]) // 用户列表
const userList = ref<any[]>([]) // 用户列表
/** 打开弹窗 */
const open = async (type: string, id?: number) => {

View File

@ -117,6 +117,7 @@ import { dateFormatter } from '@/utils/formatTime'
import * as UserGroupApi from '@/api/bpm/userGroup'
import * as UserApi from '@/api/system/user'
import UserGroupForm from './UserGroupForm.vue'
import { UserVO } from '@/api/system/user'
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
@ -131,7 +132,7 @@ const queryParams = reactive({
createTime: []
})
const queryFormRef = ref() // 搜索的表单
const userList = ref([]) // 用户列表
const userList = ref<UserVO[]>([]) // 用户列表
/** 查询列表 */
const getList = async () => {

View File

@ -16,7 +16,7 @@
<!-- 流程属性器负责编辑每个流程节点的属性 -->
<MyProcessPenal
key="penal"
:bpmnModeler="modeler"
:bpmnModeler="modeler as any"
:prefix="controlForm.prefix"
class="process-panel"
:model="model"

View File

@ -219,7 +219,7 @@
<MyProcessViewer
key="designer"
v-model="bpmnXML"
:value="bpmnXML"
:value="bpmnXML as any"
v-bind="bpmnControlForm"
:prefix="bpmnControlForm.prefix"
/>

View File

@ -28,7 +28,7 @@ const props = defineProps({
id: propTypes.number.def(undefined)
})
const detailLoading = ref(false) // 表单的加载中
const detailData = ref({}) // 详情数据
const detailData = ref<any>({}) // 详情数据
const queryId = query.id as unknown as number // 从 URL 传递过来的 id 编号
/** 获得数据 */

View File

@ -43,7 +43,7 @@
</el-col>
</el-card>
<!-- 流程图预览 -->
<ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML" />
<ProcessInstanceBpmnViewer :bpmn-xml="bpmnXML as any" />
</ContentWrap>
</template>
<script setup lang="ts" name="BpmProcessInstanceCreate">

View File

@ -33,6 +33,12 @@
import FcDesigner from '@form-create/designer'
import { useClipboard } from '@vueuse/core'
import { isString } from '@/utils/is'
import hljs from 'highlight.js' // 导入代码高亮文件
import 'highlight.js/styles/github.css' // 导入代码高亮样式
import xml from 'highlight.js/lib/languages/java'
import json from 'highlight.js/lib/languages/json'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息
@ -112,10 +118,6 @@ const copy = async (text: string) => {
/**
* 代码高亮
*/
import hljs from 'highlight.js' // 导入代码高亮文件
import 'highlight.js/styles/github.css' // 导入代码高亮样式
import xml from 'highlight.js/lib/languages/java'
import json from 'highlight.js/lib/languages/json'
const highlightedCode = (code) => {
// 处理语言和代码
let language = 'json'

View File

@ -59,6 +59,14 @@ import { useClipboard } from '@vueuse/core'
import { handleTree2 } from '@/utils/tree'
import * as CodegenApi from '@/api/infra/codegen'
import hljs from 'highlight.js' // 导入代码高亮文件
import 'highlight.js/styles/github.css' // 导入代码高亮样式
import java from 'highlight.js/lib/languages/java'
import xml from 'highlight.js/lib/languages/java'
import javascript from 'highlight.js/lib/languages/javascript'
import sql from 'highlight.js/lib/languages/sql'
import typescript from 'highlight.js/lib/languages/typescript'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
@ -184,13 +192,6 @@ const copy = async (text: string) => {
/**
* 代码高亮
*/
import hljs from 'highlight.js' // 导入代码高亮文件
import 'highlight.js/styles/github.css' // 导入代码高亮样式
import java from 'highlight.js/lib/languages/java'
import xml from 'highlight.js/lib/languages/java'
import javascript from 'highlight.js/lib/languages/javascript'
import sql from 'highlight.js/lib/languages/sql'
import typescript from 'highlight.js/lib/languages/typescript'
const highlightedCode = (item) => {
const language = item.filePath.substring(item.filePath.lastIndexOf('.') + 1)
const result = hljs.highlight(language, item.code || '', true)

View File

@ -1,7 +1,6 @@
<template>
<doc-alert title="Redis 缓存" url="https://doc.iocoder.cn/redis-cache/" />
<doc-alert title="本地缓存" url="https://doc.iocoder.cn/local-cache/" />
<el-scrollbar height="calc(100vh - 88px - 40px - 50px)">
<el-row>
<!-- 基本信息 -->
@ -51,127 +50,224 @@
<!-- 命令统计 -->
<el-col :span="12" class="mt-3">
<el-card :gutter="12" shadow="hover">
<div ref="commandStatsRef" class="h-88"></div>
<Echart :options="commandStatsRefChika" :height="420" />
</el-card>
</el-col>
<!-- 内存使用量统计 -->
<el-col :span="12" class="mt-3">
<el-card class="ml-3" :gutter="12" shadow="hover">
<div ref="usedmemory" class="h-88"></div>
<Echart :options="usedmemoryEchartChika" :height="420" />
</el-card>
</el-col>
</el-row>
</el-scrollbar>
</template>
<script setup lang="ts" name="InfraRedis">
import * as echarts from 'echarts'
<script setup lang="ts">
import echarts from '@/plugins/echarts'
import { GaugeChart } from 'echarts/charts'
import { ToolboxComponent } from 'echarts/components'
import * as RedisApi from '@/api/infra/redis'
import { RedisMonitorInfoVO } from '@/api/infra/redis/types'
const cache = ref<RedisMonitorInfoVO>()
// 基本信息
const readRedisInfo = async () => {
const data = await RedisApi.getCache()
cache.value = data
loadEchartOptions(data.commandStats)
}
// 图表
const commandStatsRef = ref<HTMLElement>()
const usedmemory = ref<HTMLDivElement>()
const loadEchartOptions = (stats) => {
const commandStats = [] as any[]
const nameList = [] as string[]
stats.forEach((row) => {
commandStats.push({
name: row.command,
value: row.calls
})
nameList.push(row.command)
})
const commandStatsInstance = echarts.init(commandStatsRef.value!, 'macarons')
commandStatsInstance.setOption({
title: {
text: '命令统计',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
type: 'scroll',
orient: 'vertical',
right: 30,
top: 10,
bottom: 20,
data: nameList,
textStyle: {
color: '#a1a1a1'
// 内存使用情况
const usedmemoryEchartChika = reactive({
title: {
// 仪表盘标题。
text: '内存使用情况',
left: 'center',
show: true, // 是否显示标题,默认 true。
offsetCenter: [0, '20%'], //相对于仪表盘中心的偏移位置,数组第一项是水平方向的偏移,第二项是垂直方向的偏移。可以是绝对的数值,也可以是相对于仪表盘半径的百分比。
color: 'yellow', // 文字的颜色,默认 #333。
fontSize: 20 // 文字的字体大小,默认 15。
},
toolbox: {
show: false,
feature: {
restore: { show: true },
saveAsImage: { show: true }
}
},
series: [
{
name: '峰值',
type: 'gauge',
min: 0,
max: 50,
splitNumber: 10,
//这是指针的颜色
color: '#F5C74E',
radius: '85%',
center: ['50%', '50%'],
startAngle: 225,
endAngle: -45,
axisLine: {
// 坐标轴线
lineStyle: {
// 属性lineStyle控制线条样式
color: [
[0.2, '#7FFF00'],
[0.8, '#00FFFF'],
[1, '#FF0000']
],
//width: 6 外框的大小(环的宽度)
width: 10
}
},
axisTick: {
// 坐标轴小标记
//里面的线长是5短线
length: 5, // 属性length控制线长
lineStyle: {
// 属性lineStyle控制线条样式
color: '#76D9D7'
}
},
splitLine: {
// 分隔线
length: 20, // 属性length控制线长
lineStyle: {
// 属性lineStyle详见lineStyle控制线条样式
color: '#76D9D7'
}
},
axisLabel: {
color: '#76D9D7',
distance: 15,
fontSize: 15
},
pointer: {
// 指针的大小
width: 7,
show: true
},
detail: {
textStyle: {
fontWeight: 'normal',
// 里面文字下的数值大小50
fontSize: 15,
color: '#FFFFFF'
},
valueAnimation: true
},
progress: {
show: true
}
},
series: [
{
name: '命令',
type: 'pie',
radius: [20, 120],
center: ['40%', '60%'],
data: commandStats,
roseType: 'radius',
}
]
})
// 指令使用情况
const commandStatsRefChika = reactive({
title: {
text: '命令统计',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
type: 'scroll',
orient: 'vertical',
right: 30,
top: 10,
bottom: 20,
data: [] as any[],
textStyle: {
color: '#a1a1a1'
}
},
series: [
{
name: '命令',
type: 'pie',
radius: [20, 120],
center: ['40%', '60%'],
data: [] as any[],
roseType: 'radius',
label: {
show: true
},
emphasis: {
label: {
show: true
},
emphasis: {
label: {
show: true
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
]
})
}
]
})
const usedMemoryInstance = echarts.init(usedmemory.value!, 'macarons')
usedMemoryInstance.setOption({
title: {
text: '内存使用情况',
left: 'center'
},
tooltip: {
formatter: '{b} <br/>{a} : ' + cache.value!.info.used_memory_human
},
series: [
{
name: '峰值',
type: 'gauge',
min: 0,
max: 100,
progress: {
show: true
},
detail: {
formatter: cache.value!.info.used_memory_human
},
data: [
{
value: parseFloat(cache.value!.info.used_memory_human),
name: '内存消耗'
}
]
}
]
})
/** 加载数据 */
const getSummary = () => {
// 初始化命令图表
initCommandStatsChart()
usedMemoryInstance()
}
onBeforeMount(() => {
// TODO @hiiwbs 微信,优化使用 Echart 组件
/** 命令使用情况 */
const initCommandStatsChart = async () => {
usedmemoryEchartChika.series[0].data = []
// 发起请求
try {
const data = await RedisApi.getCache()
cache.value = data
// 处理数据
const commandStats = [] as any[]
const nameList = [] as string[]
data.commandStats.forEach((row) => {
commandStats.push({
name: row.command,
value: row.calls
})
nameList.push(row.command)
})
commandStatsRefChika.legend.data = nameList
commandStatsRefChika.series[0].data = commandStats
} catch {}
}
const usedMemoryInstance = async () => {
try {
const data = await RedisApi.getCache()
cache.value = data
// 仪表盘详情,用于显示数据。
usedmemoryEchartChika.series[0].detail = {
show: true, // 是否显示详情,默认 true。
offsetCenter: [0, '50%'], // 相对于仪表盘中心的偏移位置,数组第一项是水平方向的偏移,第二项是垂直方向的偏移。可以是绝对的数值,也可以是相对于仪表盘半径的百分比。
color: 'auto', // 文字的颜色,默认 auto。
fontSize: 30, // 文字的字体大小,默认 15。
formatter: cache.value!.info.used_memory_human // 格式化函数或者字符串
}
usedmemoryEchartChika.series[0].data[0] = {
value: cache.value!.info.used_memory_human,
name: '内存消耗'
}
console.log(cache.value!.info)
usedmemoryEchartChika.tooltip = {
formatter: '{b} <br/>{a} : ' + cache.value!.info.used_memory_human
}
} catch {}
}
/** 初始化 **/
onMounted(() => {
echarts.use([ToolboxComponent])
echarts.use([GaugeChart])
// 读取 redis 信息
readRedisInfo()
// 加载数据
getSummary()
})
</script>

View File

@ -0,0 +1,125 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="120px"
v-loading="formLoading"
>
<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="快递公司logo" prop="logo">
<UploadImg v-model="formData.logo" :limit="1" :is-show-tip="false" />
<div style="font-size: 10px" class="pl-10px">推荐 180x180 图片分辨率</div>
</el-form-item>
<el-form-item label="分类排序" prop="sort">
<el-input-number v-model="formData.sort" controls-position="right" :min="0" />
</el-form-item>
<el-form-item label="开启状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts" name="ExpressForm">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants'
import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({
id: undefined,
code: '',
name: '',
logo: '',
sort: 0,
status: CommonStatusEnum.ENABLE
})
const formRules = reactive({
code: [{ required: true, message: '快递编码不能为空', trigger: 'blur' }],
name: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }],
logo: [{ required: true, message: '分类图片不能为空', trigger: 'blur' }],
sort: [{ required: true, message: '分类排序不能为空', trigger: 'blur' }],
status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
// 修改时,设置数据
if (id) {
formLoading.value = true
try {
formData.value = await DeliveryExpressApi.getDeliveryExpress(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
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 DeliveryExpressApi.DeliveryExpressVO
if (formType.value === 'create') {
await DeliveryExpressApi.createDeliveryExpress(data)
message.success(t('common.createSuccess'))
} else {
await DeliveryExpressApi.updateDeliveryExpress(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
// 发送操作成功的事件
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: '',
picUrl: '',
bigPicUrl: '',
status: CommonStatusEnum.ENABLE
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,183 @@
<template>
<!-- 搜索工作栏 -->
<ContentWrap>
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="100px"
>
<el-form-item label="快递公司编码" prop="code">
<el-input
v-model="queryParams.code"
placeholder="请输快递公司编码"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="快递公司名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输快递公司名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<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"
plain
@click="openForm('create')"
v-hasPermi="['trade:delivery:express:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['trade:delivery:express:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list">
<el-table-column label="快递公司编号" prop="code" />
<el-table-column label="快递公司名称" prop="name" />
<el-table-column label="快递公司 logo " prop="logo">
<template #default="scope">
<img v-if="scope.row.logo" :src="scope.row.logo" alt="快递公司logo" class="h-25px" />
</template>
</el-table-column>
<el-table-column label="排序" align="center" prop="sort" />
<el-table-column label="开启状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
width="180"
:formatter="dateFormatter"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['trade:delivery:express:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['trade:delivery:express:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<ExpressForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts" name="Express">
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
import ExpressForm from './ExpressForm.vue'
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const total = ref(0) // 列表的总页数
const loading = ref(true) // 列表的加载中
const list = ref<any[]>([]) // 列表的数据
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: '',
name: ''
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await DeliveryExpressApi.getDeliveryExpressPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await DeliveryExpressApi.deleteDeliveryExpress(id)
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const data = await DeliveryExpressApi.exportDeliveryExpressApi(queryParams)
download.excel(data, '快递公司.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -0,0 +1,78 @@
<template>
<div>
<el-form ref="formRef" :model="replyForm" :rules="rules" label-width="80px">
<el-form-item label="消息类型" prop="requestMessageType" v-if="msgType === MsgType.Message">
<el-select v-model="replyForm.requestMessageType" placeholder="请选择">
<template v-for="dict in getDictOptions(DICT_TYPE.MP_MESSAGE_TYPE)" :key="dict.value">
<el-option
v-if="RequestMessageTypes.includes(dict.value)"
:label="dict.label"
:value="dict.value"
/>
</template>
</el-select>
</el-form-item>
<el-form-item label="匹配类型" prop="requestMatch" v-if="msgType === MsgType.Keyword">
<el-select v-model="replyForm.requestMatch" placeholder="请选择匹配类型" clearable>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="关键词" prop="requestKeyword" v-if="msgType === MsgType.Keyword">
<el-input v-model="replyForm.requestKeyword" placeholder="请输入内容" clearable />
</el-form-item>
<el-form-item label="回复消息">
<WxReplySelect v-model="reply" />
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts" name="ReplyForm">
import WxReplySelect, { type Reply } from '@/views/mp/components/wx-reply'
import type { FormInstance } from 'element-plus'
import { MsgType } from './types'
import { DICT_TYPE, getDictOptions, getIntDictOptions } from '@/utils/dict'
const props = defineProps<{
modelValue: any
reply: Reply
msgType: MsgType
}>()
const emit = defineEmits<{
(e: 'update:reply', v: Reply)
(e: 'update:modelValue', v: any)
}>()
const reply = computed<Reply>({
get: () => props.reply,
set: (val) => emit('update:reply', val)
})
const replyForm = computed<any>({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const formRef = ref<FormInstance | null>(null) // 表单 ref
const RequestMessageTypes = ['text', 'image', 'voice', 'video', 'shortvideo', 'location', 'link'] // 允许选择的请求消息类型
// 表单校验
const rules = {
requestKeyword: [{ required: true, message: '请求的关键字不能为空', trigger: 'blur' }],
requestMatch: [{ required: true, message: '请求的关键字的匹配不能为空', trigger: 'blur' }]
}
defineExpose({
resetFields: () => formRef.value?.resetFields(),
validate: async () => formRef.value?.validate()
})
</script>
<style scoped></style>

View File

@ -53,38 +53,13 @@
@on-delete="onDelete"
/>
<!-- 添加或修改自动回复的对话框 -->
<!-- TODO @Dhb52 -->
<el-dialog :title="dialogTitle" v-model="showFormDialog" width="800px" destroy-on-close>
<el-form ref="formRef" :model="replyForm" :rules="rules" label-width="80px">
<el-form-item label="消息类型" prop="requestMessageType" v-if="msgType === MsgType.Message">
<el-select v-model="replyForm.requestMessageType" placeholder="请选择">
<template v-for="dict in getDictOptions(DICT_TYPE.MP_MESSAGE_TYPE)" :key="dict.value">
<el-option
v-if="RequestMessageTypes.includes(dict.value)"
:label="dict.label"
:value="dict.value"
/>
</template>
</el-select>
</el-form-item>
<el-form-item label="匹配类型" prop="requestMatch" v-if="msgType === MsgType.Keyword">
<el-select v-model="replyForm.requestMatch" placeholder="请选择匹配类型" clearable>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="关键词" prop="requestKeyword" v-if="msgType === MsgType.Keyword">
<el-input v-model="replyForm.requestKeyword" placeholder="请输入内容" clearable />
</el-form-item>
<el-form-item label="回复消息">
<WxReplySelect v-model="reply" />
</el-form-item>
</el-form>
<el-dialog
:title="isCreating ? '新增自动回复' : '修改自动回复'"
v-model="showDialog"
width="800px"
destroy-on-close
>
<ReplyForm v-model="replyForm" v-model:reply="reply" :msg-type="msgType" ref="formRef" />
<template #footer>
<el-button @click="cancel"> </el-button>
<el-button type="primary" @click="onSubmit"> </el-button>
@ -93,23 +68,22 @@
</ContentWrap>
</template>
<script setup lang="ts" name="MpAutoReply">
import WxReplySelect, { type Reply, ReplyType } from '@/views/mp/components/wx-reply'
import ReplyForm from '@/views/mp/autoReply/components/ReplyForm.vue'
import { type Reply, ReplyType } from '@/views/mp/components/wx-reply'
import WxAccountSelect from '@/views/mp/components/wx-account-select'
import * as MpAutoReplyApi from '@/api/mp/autoReply'
import { DICT_TYPE, getDictOptions, getIntDictOptions } from '@/utils/dict'
import { ContentWrap } from '@/components/ContentWrap'
import type { FormInstance, TabPaneName } from 'element-plus'
import type { TabPaneName } from 'element-plus'
import ReplyTable from './components/ReplyTable.vue'
import { MsgType } from './components/types'
const message = useMessage() // 消息
const accountId = ref(-1) // 公众号ID
const msgType = ref<MsgType>(MsgType.Keyword) // 消息类型
const RequestMessageTypes = ['text', 'image', 'voice', 'video', 'shortvideo', 'location', 'link'] // 允许选择的请求消息类型
const loading = ref(true) // 遮罩层
const total = ref(0) // 总条数
const list = ref<any[]>([]) // 自动回复列表
const formRef = ref<FormInstance | null>(null) // 表单 ref
const formRef = ref<InstanceType<typeof ReplyForm> | null>(null) // 表单 ref
// 查询参数
const queryParams = reactive({
pageNo: 1,
@ -117,19 +91,14 @@ const queryParams = reactive({
accountId: accountId
})
const dialogTitle = ref('') // 弹出层标题
const showFormDialog = ref(false) // 是否显示弹出层
const isCreating = ref(false) // 是否新建(否则编辑)
const showDialog = ref(false) // 是否显示弹出层
const replyForm = ref<any>({}) // 表单参数
// 回复消息
const reply = ref<Reply>({
type: ReplyType.Text,
accountId: -1
})
// 表单校验
const rules = {
requestKeyword: [{ required: true, message: '请求的关键字不能为空', trigger: 'blur' }],
requestMatch: [{ required: true, message: '请求的关键字的匹配不能为空', trigger: 'blur' }]
}
/** 侦听账号变化 */
const onAccountChanged = (id: number) => {
@ -174,8 +143,8 @@ const onCreate = () => {
accountId: queryParams.accountId
}
dialogTitle.value = '新增自动回复'
showFormDialog.value = true
isCreating.value = true
showDialog.value = true
}
/** 修改按钮操作 */
@ -207,8 +176,8 @@ const onUpdate = async (id: number) => {
}
// 打开表单
dialogTitle.value = '修改自动回复'
showFormDialog.value = true
isCreating.value = false
showDialog.value = true
}
/** 删除按钮操作 */
@ -220,8 +189,7 @@ const onDelete = async (id: number) => {
}
const onSubmit = async () => {
const valid = await formRef.value?.validate()
if (!valid) return
await formRef.value?.validate()
// 处理回复消息
const submitForm: any = { ...replyForm.value }
@ -245,7 +213,7 @@ const onSubmit = async () => {
message.success('新增成功')
}
showFormDialog.value = false
showDialog.value = false
await getList()
}
@ -264,7 +232,7 @@ const reset = () => {
// 取消按钮
const cancel = () => {
showFormDialog.value = false
showDialog.value = false
reset()
}
</script>

View File

@ -122,7 +122,9 @@ const open = async (type: string, id?: number, dictType?: string) => {
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
formData.value.dictType = dictType
if (dictType) {
formData.value.dictType = dictType
}
// 修改时,设置数据
if (id) {
formLoading.value = true

View File

@ -17,9 +17,9 @@
<el-select v-model="formData.type" clearable placeholder="请选择公告类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_NOTICE_TYPE)"
:key="parseInt(dict.value)"
:key="parseInt(dict.value as any)"
:label="dict.label"
:value="parseInt(dict.value)"
:value="parseInt(dict.value as any)"
/>
</el-select>
</el-form-item>
@ -27,9 +27,9 @@
<el-select v-model="formData.status" clearable placeholder="请选择状态">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key="parseInt(dict.value)"
:key="parseInt(dict.value as any)"
:label="dict.label"
:value="parseInt(dict.value)"
:value="parseInt(dict.value as any)"
/>
</el-select>
</el-form-item>

View File

@ -44,7 +44,6 @@
</Dialog>
</template>
<script lang="ts" name="SystemNotifyTemplateSendForm" setup>
import * as SmsTemplateApi from '@/api/system/sms/smsTemplate'
import * as UserApi from '@/api/system/user'
import * as NotifyTemplateApi from '@/api/system/notify/template'
const message = useMessage() // 消息弹窗
@ -102,8 +101,8 @@ const submitForm = async () => {
// 提交请求
formLoading.value = true
try {
const data = formData.value as SmsTemplateApi.SendSmsReqVO
const logId = await SmsTemplateApi.sendSms(data)
const data = formData.value as unknown as NotifyTemplateApi.NotifySendReqVO
const logId = await NotifyTemplateApi.sendNotify(data)
if (logId) {
message.success('提交发送成功!发送结果,见发送日志编号:' + logId)
}
@ -121,7 +120,7 @@ const resetForm = () => {
mobile: '',
templateCode: '',
templateParams: new Map()
}
} as any
formRef.value?.resetFields()
}
</script>

View File

@ -80,7 +80,7 @@
<el-button
link
type="danger"
@click="handleForceLogout(scope.row.id)"
@click="handleForceLogout(scope.row.accessToken)"
v-hasPermi="['system:oauth2-token:delete']"
>
强退
@ -142,12 +142,12 @@ const resetQuery = () => {
}
/** 强制退出操作 */
const handleForceLogout = async (id: number) => {
const handleForceLogout = async (accessToken: string) => {
try {
// 删除的二次确认
await message.confirm('是否要强制退出用户')
// 发起删除
await OAuth2AccessTokenApi.deleteAccessToken(id)
await OAuth2AccessTokenApi.deleteAccessToken(accessToken)
message.success(t('common.success'))
// 刷新列表
await getList()

View File

@ -117,7 +117,7 @@ const resetForm = () => {
sort: undefined,
status: CommonStatusEnum.ENABLE,
remark: ''
}
} as any
formRef.value?.resetFields()
}
</script>