新增
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert type="warning" title="温馨提示:H5设置" :closable="false" show-icon />
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<el-form ref="formRef" :model="formData" label-width="120px">
|
||||
<el-form-item label="渠道状态" required prop="status">
|
||||
<div>
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :value="1">开启</el-radio>
|
||||
<el-radio :value="0">关闭</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tips">状态为关闭时,将不对外提供服务,请谨慎操作</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="关闭后访问页面" prop="page_status">
|
||||
<el-radio-group v-model="formData.page_status">
|
||||
<el-radio :value="0">空页面</el-radio>
|
||||
<el-radio :value="1">自定义链接</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="page_url" v-if="formData.page_status == 1">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.page_url" placeholder="请输入完整的url" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="访问链接">
|
||||
<div class="flex-1 min-w-0 break-words">
|
||||
{{ formData.url }}
|
||||
<el-button v-copy="formData.url">复制</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<footer-btns v-perms="['channel.web_page_setting/setConfig']">
|
||||
<el-button type="primary" @click="handelSave">保存</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="h5Config">
|
||||
import { getH5Config, setH5Config } from '@/api/channel/h5'
|
||||
|
||||
const formData = reactive({
|
||||
status: 0,
|
||||
page_status: 0,
|
||||
page_url: '',
|
||||
url: ''
|
||||
})
|
||||
|
||||
const getDetail = async () => {
|
||||
const data = await getH5Config()
|
||||
for (const key in formData) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
}
|
||||
}
|
||||
|
||||
const handelSave = async () => {
|
||||
await setH5Config(formData)
|
||||
getDetail()
|
||||
}
|
||||
|
||||
getDetail()
|
||||
</script>
|
||||
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:填写微信开放平台开发配置,请前往微信开放平台创建应用并完成认证;网站应用配置主要用于网站微信登录和微信支付"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="160px">
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">网站应用</div>
|
||||
<el-form-item label="AppID" prop="app_id">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.app_id" placeholder="请输入AppID" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="AppSecret" prop="app_secret">
|
||||
<div>
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.app_secret" placeholder="请输入AppSecret" />
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<footer-btns v-perms="['channel.open_setting/setConfig']">
|
||||
<el-button type="primary" @click="handelSave">保存</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="wxDevConfig">
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
import { getOpenSettingConfig, setOpenSettingConfig } from '@/api/channel/open_setting'
|
||||
|
||||
const formData = reactive({
|
||||
app_id: '',
|
||||
app_secret: ''
|
||||
})
|
||||
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
const formRules = {
|
||||
app_id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入AppID',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
app_secret: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入AppSecret',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const getDetail = async () => {
|
||||
const data = await getOpenSettingConfig()
|
||||
for (const key in formData) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
}
|
||||
}
|
||||
|
||||
const handelSave = async () => {
|
||||
await formRef.value?.validate()
|
||||
await setOpenSettingConfig(formData)
|
||||
getDetail()
|
||||
}
|
||||
|
||||
getDetail()
|
||||
</script>
|
||||
@@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:填写微信小程序开发配置,请前往微信公众平台申请小程序并完成认证"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
:label-width="appStore.isMobile ? '80px' : '160px'"
|
||||
>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">微信小程序</div>
|
||||
<el-form-item label="小程序名称" prop="name">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.name" placeholder="请输入小程序名称" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="原始ID" prop="original_id">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.original_id" placeholder="请输入原始ID" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="小程序码" prop="qr_code">
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
<material-picker v-model="formData.qr_code" :limit="1" />
|
||||
</div>
|
||||
<div class="form-tips">建议尺寸:宽400px*高400px。jpg,jpeg,png格式</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">开发者ID</div>
|
||||
<el-form-item label="AppID" prop="app_id">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.app_id" placeholder="请输入AppID" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="AppSecret" prop="app_secret">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.app_secret" placeholder="请输入AppSecret" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->开发者ID,设置AppID和AppSecret
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">服务器域名</div>
|
||||
<el-form-item label="request合法域名" prop="appId">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.request_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.request_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->服务器域名,填写https协议域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="socket合法域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.socket_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.socket_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->服务器域名,填写wss协议域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="uploadFile合法域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.upload_file_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.upload_file_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->服务器域名,填写https协议域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="downloadFile合法域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.download_file_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.download_file_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->服务器域名,填写https协议域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="udp合法域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.udp_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.udp_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->服务器域名,填写udp协议域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">业务域名</div>
|
||||
<el-form-item label="业务域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.business_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.business_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->业务域名,填写业务域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<footer-btns v-perms="['channel.mnp_settings/setConfig']">
|
||||
<el-button type="primary" @click="handelSave">保存</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="weappConfig">
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
import { getWeappConfig, setWeappConfig } from '@/api/channel/weapp'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const formData = reactive({
|
||||
name: '',
|
||||
original_id: '',
|
||||
qr_code: '',
|
||||
app_id: '',
|
||||
app_secret: '',
|
||||
business_domain: '',
|
||||
download_file_domain: '',
|
||||
request_domain: '',
|
||||
socket_domain: '',
|
||||
tcpDomain: '',
|
||||
udp_domain: '',
|
||||
upload_file_domain: ''
|
||||
})
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
const formRules = {
|
||||
app_id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入AppID',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
app_secret: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入AppSecret',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
const getDetail = async () => {
|
||||
const data = await getWeappConfig()
|
||||
for (const key in formData) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
}
|
||||
}
|
||||
|
||||
const handelSave = async () => {
|
||||
await formRef.value?.validate()
|
||||
await setWeappConfig(formData)
|
||||
getDetail()
|
||||
}
|
||||
|
||||
getDetail()
|
||||
</script>
|
||||
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:填写微信公众号开发配置,请前往微信公众平台申请服务号并完成认证"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
:label-width="appStore.isMobile ? '80px' : '160px'"
|
||||
>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">微信公众号</div>
|
||||
<el-form-item label="公众号名称" prop="name">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.name" placeholder="请输入公众号名称" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="原始ID" prop="original_id">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.original_id" placeholder="请输入原始ID" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="公众号二维码" prop="qr_code">
|
||||
<div>
|
||||
<div>
|
||||
<material-picker v-model="formData.qr_code" :limit="1" />
|
||||
</div>
|
||||
<div class="form-tips">建议尺寸:宽400px*高400px。jpg,jpeg,png格式</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">公众号开发者信息</div>
|
||||
<el-form-item label="AppID" prop="app_id">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.app_id" placeholder="请输入AppID" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="AppSecret" prop="app_secret">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.app_secret" placeholder="请输入AppSecret" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div class="form-tips">
|
||||
小程序账号登录微信公众平台,点击开发>开发设置->开发者ID,设置AppID和AppSecret
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">服务器配置</div>
|
||||
<el-form-item label="URL">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.url" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.url">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
登录微信公众平台,点击开发>基本配置>服务器配置,填写服务器地址(URL)
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="Token" prop="Token">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="w-80">
|
||||
<el-input v-model="formData.token" placeholder="请输入Token" />
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
登录微信公众平台,点击开发>基本配置>服务器配置,设置令牌Token。不填默认为“likeshop”
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="EncodingAESKey" prop="encoding_aes_key">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="w-80">
|
||||
<el-input
|
||||
v-model="formData.encoding_aes_key"
|
||||
placeholder="请输入EncodingAESKey"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
消息加密密钥由43位字符组成,字符范围为A-Z,a-z,0-9
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="消息加密方式" required prop="encryption_type">
|
||||
<div class="flex-1 min-w-0">
|
||||
<el-radio-group
|
||||
class="flex-col !items-start min-w-0"
|
||||
v-model="formData.encryption_type"
|
||||
>
|
||||
<el-radio :value="1">
|
||||
明文模式 (不使用消息体加解密功能,安全系数较低)
|
||||
</el-radio>
|
||||
|
||||
<el-radio :value="2">
|
||||
兼容模式 (明文、密文将共存,方便开发者调试和维护)
|
||||
</el-radio>
|
||||
<el-radio :value="3">
|
||||
安全模式(推荐) (消息包为纯密文,需要开发者加密和解密,安全系数高)
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="font-medium mb-7">功能设置</div>
|
||||
<el-form-item label="业务域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.business_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.business_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
登录微信公众平台,点击设置>公众号设置>功能设置,填写业务域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="JS接口安全域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.js_secure_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.js_secure_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
登录微信公众平台,点击设置>公众号设置>功能设置,填写JS接口安全域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="网页授权域名">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="sm:flex">
|
||||
<div class="mr-4 sm:w-80 flex">
|
||||
<el-input v-model="formData.web_auth_domain" disabled />
|
||||
</div>
|
||||
<el-button v-copy="formData.web_auth_domain">复制</el-button>
|
||||
</div>
|
||||
<div class="form-tips">
|
||||
登录微信公众平台,点击设置>公众号设置>功能设置,填写网页授权域名
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<footer-btns v-perms="['channel.official_account_setting/setConfig']">
|
||||
<el-button type="primary" @click="handelSave">保存</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup name="wxOaConfig">
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
import { getOaConfig, setOaConfig } from '@/api/channel/wx_oa'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const formData = reactive({
|
||||
name: '',
|
||||
original_id: ' ',
|
||||
qr_code: '',
|
||||
app_id: '',
|
||||
app_secret: '',
|
||||
url: '',
|
||||
token: '',
|
||||
encoding_aes_key: '',
|
||||
encryption_type: 1,
|
||||
business_domain: '',
|
||||
js_secure_domain: '',
|
||||
web_auth_domain: ''
|
||||
})
|
||||
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
const formRules = {
|
||||
app_id: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入AppID',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
app_secret: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入AppSecret',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const getDetail = async () => {
|
||||
const data = await getOaConfig()
|
||||
for (const key in formData) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
}
|
||||
}
|
||||
|
||||
const handelSave = async () => {
|
||||
await formRef.value?.validate()
|
||||
await setOaConfig(formData)
|
||||
getDetail()
|
||||
}
|
||||
|
||||
getDetail()
|
||||
</script>
|
||||
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts" name="wxOaMenu">
|
||||
import OaAttr from './menu_com/oa-attr.vue'
|
||||
import OaPhone from './menu_com/oa-phone.vue'
|
||||
import { useMenuOa } from './menu_com/useMenuOa'
|
||||
|
||||
const { getOaMenuFunc, handleSave, handlePublish } = useMenuOa(undefined)
|
||||
getOaMenuFunc()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="menu-oa">
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="配置微信公众号菜单,点击确认,保存菜单并发布至微信公众号"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div class="lg:flex flex-1">
|
||||
<!-- Phone -->
|
||||
<oa-phone></oa-phone>
|
||||
|
||||
<!-- Attr -->
|
||||
<div class="mt-4 lg:mt-0 max-w-[400px]">
|
||||
<oa-attr></oa-attr>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<footer-btns>
|
||||
<el-button type="primary" @click="handleSave" v-perms="['channel:oaMenu:save']">
|
||||
保存
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handlePublish" v-perms="['channel:oaMenu:publish']">
|
||||
发布
|
||||
</el-button>
|
||||
</footer-btns>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.menu-oa {
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,90 @@
|
||||
<script lang="ts" setup>
|
||||
import oaMenuForm from './oa-menu-form.vue'
|
||||
import oaMenuFormEdit from './oa-menu-form-edit.vue'
|
||||
import { useMenuOa } from './useMenuOa'
|
||||
|
||||
const menuRef = shallowRef()
|
||||
|
||||
const {
|
||||
menuList,
|
||||
menuIndex,
|
||||
handleAddSubMenu,
|
||||
handleEditSubMenu,
|
||||
handleDelMenu,
|
||||
handleDelSubMenu
|
||||
} = useMenuOa(menuRef)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Attr -->
|
||||
<template v-for="(attrItem, attrIndex) in menuList" :key="attrIndex">
|
||||
<div class="flex-1 oa-attr min-w-0" v-show="attrIndex === menuIndex">
|
||||
<div class="text-base oa-attr-title">菜单配置</div>
|
||||
|
||||
<del-wrap @close="handleDelMenu(menuIndex)">
|
||||
<div class="flex items-center w-full p-4 mt-4 rounded bg-fill-light">
|
||||
<oa-menu-form
|
||||
ref="menuRef"
|
||||
modular="master"
|
||||
v-model:name="attrItem.name"
|
||||
v-model:menuType="attrItem.has_menu"
|
||||
v-model:visitType="attrItem.type"
|
||||
v-model:url="attrItem.url"
|
||||
v-model:appId="attrItem.appid"
|
||||
v-model:pagePath="attrItem.pagepath"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<!-- 编辑子菜单 -->
|
||||
<ul>
|
||||
<li
|
||||
class="flex"
|
||||
v-for="(subItem, subIndex) in attrItem.sub_button"
|
||||
:key="subIndex"
|
||||
style="padding: 8px"
|
||||
>
|
||||
<span class="mr-auto">{{ subItem.name }}</span>
|
||||
<!-- 编辑子菜单 -->
|
||||
<oa-menu-form-edit
|
||||
modular="edit"
|
||||
:subItem="subItem"
|
||||
@edit="handleEditSubMenu($event, subIndex)"
|
||||
>
|
||||
<el-button link>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</oa-menu-form-edit>
|
||||
|
||||
<!-- 删除子菜单 -->
|
||||
<popup @confirm="handleDelSubMenu(menuIndex, subIndex)">
|
||||
是否删除当前子菜单?
|
||||
<template #trigger>
|
||||
<el-button link>
|
||||
<el-icon class="ml-5"><Delete /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</popup>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- 新增子菜单 -->
|
||||
<oa-menu-form-edit modular="add" @add="handleAddSubMenu">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
:disabled="attrItem.sub_button.length >= 5"
|
||||
>
|
||||
添加子菜单({{ attrItem.sub_button.length }}/5)
|
||||
</el-button>
|
||||
</oa-menu-form-edit>
|
||||
</div>
|
||||
</oa-menu-form>
|
||||
</div>
|
||||
</del-wrap>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.oa-attr {
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,73 @@
|
||||
<script lang="ts" setup>
|
||||
import oaMenuForm from './oa-menu-form.vue'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'add', value: any): void
|
||||
(event: 'edit', value: any): void
|
||||
}>()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modular: string
|
||||
subItem?: any
|
||||
}>(),
|
||||
{
|
||||
modular: 'edit',
|
||||
subItem: {}
|
||||
}
|
||||
)
|
||||
|
||||
const menuFormEditRef = shallowRef()
|
||||
const menuFromPopupRef = shallowRef()
|
||||
|
||||
const form = {
|
||||
name: '',
|
||||
type: 'view',
|
||||
url: '',
|
||||
appid: '',
|
||||
pagepath: ''
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (Object.keys(props.subItem).length != 0) {
|
||||
for (const key in form) {
|
||||
//@ts-ignore
|
||||
form[key] = props.subItem[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleRules = async () => {
|
||||
await menuFormEditRef.value.menuFormRef.validate()
|
||||
if (props.modular === 'edit') {
|
||||
emit('edit', { ...form })
|
||||
} else {
|
||||
emit('add', { ...form })
|
||||
}
|
||||
menuFromPopupRef.value.close()
|
||||
menuFormEditRef.value.menuFormRef.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<popup
|
||||
ref="menuFromPopupRef"
|
||||
async
|
||||
:clickModalClose="false"
|
||||
:title="`${modular === 'add' ? '新增' : '编辑'}子菜单`"
|
||||
@confirm="handleRules"
|
||||
>
|
||||
<oa-menu-form
|
||||
ref="menuFormEditRef"
|
||||
modular="secondary"
|
||||
v-model:name="form.name"
|
||||
v-model:visitType="form.type"
|
||||
v-model:url="form.url"
|
||||
v-model:appId="form.appid"
|
||||
v-model:pagePath="form.pagepath"
|
||||
></oa-menu-form>
|
||||
<template #trigger>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</popup>
|
||||
</template>
|
||||
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<el-form ref="menuFormRef" :rules="rules" :model="menuForm" label-width="100px">
|
||||
<!-- 菜单名称 -->
|
||||
<el-form-item :label="modular === 'master' ? '主菜单名称' : '子菜单名称'" prop="name">
|
||||
<el-input v-model="menuForm.name" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 菜单类型 -->
|
||||
<el-form-item label="主菜单类型" prop="menuType" v-if="modular === 'master'">
|
||||
<el-radio-group v-model="menuForm.menuType">
|
||||
<el-radio :value="false">不配置子菜单</el-radio>
|
||||
<el-radio :value="true">配置子菜单</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="" v-if="menuForm.menuType && modular === 'master'">
|
||||
<slot></slot>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="!menuForm.menuType">
|
||||
<!-- 跳转链接 -->
|
||||
<el-form-item label="跳转链接" prop="visitType">
|
||||
<el-radio-group v-model="menuForm.visitType">
|
||||
<el-radio value="view">网页</el-radio>
|
||||
<el-radio value="miniprogram">小程序</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 网址 -->
|
||||
<el-form-item label="网址" prop="url">
|
||||
<el-input v-model="menuForm.url" />
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="menuForm.visitType == 'miniprogram'">
|
||||
<!-- AppId -->
|
||||
<el-form-item label="AppId" prop="appId">
|
||||
<el-input v-model="menuForm.appId" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 路径 -->
|
||||
<el-form-item label="路径" prop="pagePath">
|
||||
<el-input v-model="menuForm.pagePath" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</template>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
import { rules } from './useMenuOa'
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:name',
|
||||
'update:menuType',
|
||||
'update:visitType',
|
||||
'update:url',
|
||||
'update:appId',
|
||||
'update:pagePath'
|
||||
])
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modular?: string
|
||||
name?: string
|
||||
menuType?: boolean
|
||||
visitType?: string
|
||||
url?: string
|
||||
appId?: string
|
||||
pagePath?: string
|
||||
}>(),
|
||||
{
|
||||
modular: 'master',
|
||||
name: '',
|
||||
menuType: false,
|
||||
visitType: 'view',
|
||||
url: '',
|
||||
appId: '',
|
||||
pagePath: ''
|
||||
}
|
||||
)
|
||||
|
||||
const menuFormRef = shallowRef<FormInstance>()
|
||||
// 表单数据
|
||||
const menuForm = ref({ ...props })
|
||||
|
||||
watch(
|
||||
() => props,
|
||||
(value) => {
|
||||
menuForm.value = value
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.modular === 'master') {
|
||||
emit('update:menuType', menuForm.value.menuType)
|
||||
}
|
||||
emit('update:name', menuForm.value.name)
|
||||
emit('update:visitType', menuForm.value.visitType)
|
||||
emit('update:url', menuForm.value.url)
|
||||
emit('update:appId', menuForm.value.appId)
|
||||
emit('update:pagePath', menuForm.value.pagePath)
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
menuFormRef
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,122 @@
|
||||
<script lang="ts" setup>
|
||||
import useSettingStore from '@/stores/modules/setting'
|
||||
|
||||
import { useMenuOa } from './useMenuOa'
|
||||
|
||||
// 菜单颜色(这里采用全局颜色)
|
||||
const settingStore = useSettingStore()
|
||||
const themeColor = computed(() => settingStore.theme || '#4A5DFF')
|
||||
|
||||
const { menuList, menuIndex, handleAddMenu } = useMenuOa(useMenuOa)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Phone -->
|
||||
<div class="oa-phone mr-[35px]">
|
||||
<div class="oa-phone-content"></div>
|
||||
|
||||
<div class="flex oa-phone-menu">
|
||||
<div class="flex items-center justify-center oa-phone-menu-switch">
|
||||
<el-icon>
|
||||
<Grid />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<template v-for="(menuItem, i) in menuList" :key="i">
|
||||
<div class="relative flex-1" @click="menuIndex = i">
|
||||
<!-- 一级菜单 -->
|
||||
<div
|
||||
class="flex items-center justify-center flex-1 text-sm oa-phone-menu-item"
|
||||
:class="{ 'active-menu': menuIndex === i }"
|
||||
>
|
||||
{{ menuItem.name }}
|
||||
</div>
|
||||
|
||||
<!-- 二级菜单 -->
|
||||
<div
|
||||
class="oa-phone-menu-subitem"
|
||||
v-show="menuItem.sub_button.length && menuItem.has_menu"
|
||||
>
|
||||
<template v-for="(subItem, index2) in menuItem.sub_button" :key="index2">
|
||||
<div class="oa-phone-menu-subitem-title">
|
||||
{{ subItem.name }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 新增菜单 -->
|
||||
<template v-if="menuList.length <= 2">
|
||||
<div class="flex items-center justify-center flex-1 h-full" @click="handleAddMenu">
|
||||
<el-icon>
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.oa-phone {
|
||||
width: 260px;
|
||||
height: 461px;
|
||||
border: 1px solid #e5e5ea;
|
||||
flex: none;
|
||||
&-content {
|
||||
height: 420px;
|
||||
border-bottom: 1px solid #e5e5ea;
|
||||
}
|
||||
|
||||
&-menu {
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
|
||||
&-switch {
|
||||
width: 40px;
|
||||
height: 100%;
|
||||
border-right: 1px solid #e5e5ea;
|
||||
}
|
||||
|
||||
// 一级菜单
|
||||
&-item {
|
||||
height: 100%;
|
||||
border-right: 1px solid #e5e5ea;
|
||||
}
|
||||
|
||||
&-item:nth-child(4) {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.active-menu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.active-menu::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 41px;
|
||||
top: -1px;
|
||||
position: absolute;
|
||||
border: 1px solid v-bind(themeColor);
|
||||
}
|
||||
|
||||
// 二级菜单
|
||||
&-subitem {
|
||||
width: 98%;
|
||||
left: 2px;
|
||||
bottom: calc(100% + 10px);
|
||||
position: absolute;
|
||||
border: 1px solid #e5e5ea;
|
||||
border-top: none;
|
||||
|
||||
&-title {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e5e5ea;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,167 @@
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import type { Menu } from '@/api/channel/wx_oa'
|
||||
import { getOaMenu, setOaMenuPublish, setOaMenuSave } from '@/api/channel/wx_oa'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
// 菜单实例
|
||||
export const menuRef = shallowRef()
|
||||
// 菜单数据
|
||||
const menuList = ref<Menu[]>([])
|
||||
const menuIndex = ref<number>(0)
|
||||
|
||||
// 校验
|
||||
export const rules = reactive<FormRules>({
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
{
|
||||
min: 1,
|
||||
max: 12,
|
||||
message: '长度限制12个字符',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
menuType: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
visitType: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
url: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
{
|
||||
pattern:
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
/(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/,
|
||||
message: '请输入合法的网址链接',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
appId: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
],
|
||||
pagePath: [
|
||||
{
|
||||
required: true,
|
||||
message: '必填项不能为空',
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export const useMenuOa = (ref: any) => {
|
||||
if (ref) menuRef.value = ref
|
||||
|
||||
// 添加主菜单
|
||||
const handleAddMenu = () => {
|
||||
menuList.value.push({
|
||||
name: '菜单名称',
|
||||
has_menu: false,
|
||||
type: 'view',
|
||||
url: '',
|
||||
appid: '',
|
||||
pagepath: '',
|
||||
sub_button: []
|
||||
})
|
||||
}
|
||||
|
||||
// 添加子菜单
|
||||
const handleAddSubMenu = (event?: Menu) => {
|
||||
const index = menuIndex.value
|
||||
if (menuList.value[index].sub_button.length >= 5) {
|
||||
feedback.msgError('已添加上限~')
|
||||
return
|
||||
}
|
||||
menuList.value[index].sub_button.push(event)
|
||||
}
|
||||
|
||||
// 编辑子菜单
|
||||
const handleEditSubMenu = (event: Menu, subIndex: number) => {
|
||||
const index = menuIndex.value
|
||||
menuList.value[index].sub_button[subIndex] = event
|
||||
}
|
||||
|
||||
// 删除主菜单
|
||||
const handleDelMenu = (index: number) => {
|
||||
if (index != 0) {
|
||||
menuIndex.value--
|
||||
}
|
||||
menuList.value.splice(index, 1)
|
||||
}
|
||||
|
||||
// 删除子菜单
|
||||
const handleDelSubMenu = (index: number, subIndex: number) => {
|
||||
menuList.value[index].sub_button.splice(subIndex, 1)
|
||||
}
|
||||
|
||||
// 获取菜单
|
||||
const getOaMenuFunc = async () => {
|
||||
try {
|
||||
menuList.value = await getOaMenu()
|
||||
} catch (error) {
|
||||
console.log('获取菜单=>', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 保存菜单
|
||||
const handleSave = async () => {
|
||||
const refs = menuRef.value.value
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
try {
|
||||
await refs[i].menuFormRef.validate()
|
||||
} catch (error) {
|
||||
menuIndex.value = i
|
||||
return
|
||||
}
|
||||
}
|
||||
await setOaMenuSave(menuList.value)
|
||||
}
|
||||
|
||||
// 保存菜单
|
||||
const handlePublish = async () => {
|
||||
const refs = menuRef.value.value
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
try {
|
||||
await refs[i].menuFormRef.validate()
|
||||
} catch (error) {
|
||||
menuIndex.value = i
|
||||
return
|
||||
}
|
||||
}
|
||||
await setOaMenuPublish(menuList.value)
|
||||
}
|
||||
|
||||
return {
|
||||
menuList,
|
||||
menuIndex,
|
||||
handleAddMenu,
|
||||
handleAddSubMenu,
|
||||
handleEditSubMenu,
|
||||
handleDelMenu,
|
||||
handleDelSubMenu,
|
||||
getOaMenuFunc,
|
||||
handleSave,
|
||||
handlePublish
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:1.粉丝在公众号发送内容时,系统无法匹配情况下发送启用的默认文本回复;2.同时只能启用一个默认回复。"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div>
|
||||
<el-button class="mb-4" type="primary" @click="handleAdd()">
|
||||
<template #icon>
|
||||
<icon name="el-icon-Plus" />
|
||||
</template>
|
||||
新增
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table size="large" :data="pager.lists" v-loading="pager.loading">
|
||||
<el-table-column label="规则名称" prop="name" min-width="120" />
|
||||
<el-table-column label="回复类型" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{ getContentType(row.content_type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复内容" prop="content" min-width="120" />
|
||||
<el-table-column label="状态" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="changeStatus(row.id)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" prop="sort" min-width="120" />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
|
||||
<el-button type="danger" link @click="handleDelete(row.id)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="flex justify-end mt-4">
|
||||
<pagination v-model="pager" @change="getLists" />
|
||||
</div>
|
||||
</el-card>
|
||||
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { changeOaReplyStatus, getOaReplyList, oaReplyDel } from '@/api/channel/wx_oa'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
import EditPopup from './edit.vue'
|
||||
|
||||
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
|
||||
const showEdit = ref(false)
|
||||
|
||||
const getContentType = computed(() => {
|
||||
return (val: number) => {
|
||||
switch (val) {
|
||||
case 1:
|
||||
return '文本'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { pager, getLists } = usePaging({
|
||||
fetchFun: getOaReplyList,
|
||||
params: {
|
||||
reply_type: 3
|
||||
}
|
||||
})
|
||||
|
||||
const handleAdd = async () => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('add', 3)
|
||||
}
|
||||
|
||||
const handleEdit = async (data: any) => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('edit', 3)
|
||||
editRef.value?.getDetail(data)
|
||||
}
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
await feedback.confirm('确定要删除?')
|
||||
await oaReplyDel({ id })
|
||||
feedback.msgSuccess('删除成功')
|
||||
getLists()
|
||||
}
|
||||
|
||||
const changeStatus = async (id: number) => {
|
||||
try {
|
||||
await changeOaReplyStatus({ id })
|
||||
getLists()
|
||||
} catch (error) {
|
||||
getLists()
|
||||
}
|
||||
}
|
||||
|
||||
getLists()
|
||||
</script>
|
||||
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="edit-popup">
|
||||
<popup
|
||||
ref="popupRef"
|
||||
:title="popupTitle"
|
||||
:async="true"
|
||||
width="500px"
|
||||
@confirm="handleSubmit"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
label-width="84px"
|
||||
:rules="formRules"
|
||||
class="pr-10"
|
||||
>
|
||||
<el-form-item label="规则名称" prop="name">
|
||||
<div class="flex-1">
|
||||
<el-input v-model="formData.name" placeholder="请输入规则名称" />
|
||||
<div class="form-tips">方便通过名称管理关注回复内容</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键词" prop="keyword" v-if="formData.reply_type == 2">
|
||||
<div class="flex-1">
|
||||
<el-input v-model="formData.keyword" placeholder="请输入关键词" />
|
||||
<div class="form-tips">方便通过名称管理关注回复内容</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="匹配方式" prop="matching_type" v-if="formData.reply_type == 2">
|
||||
<div class="flex-1">
|
||||
<el-radio-group v-model="formData.matching_type">
|
||||
<el-radio :value="1">全匹配</el-radio>
|
||||
<el-radio :value="2">模糊匹配</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tips">模糊匹配时,关键词部分匹配用户输入的内容即可</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="回复类型" prop="content_type" :min="0">
|
||||
<div class="flex-1">
|
||||
<el-radio-group v-model="formData.content_type">
|
||||
<el-radio :value="1">文本</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tips">暂时只支持文本类型</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="回复内容" prop="content">
|
||||
<div class="flex-1">
|
||||
<el-input
|
||||
v-model="formData.content"
|
||||
:autosize="{ minRows: 4, maxRows: 4 }"
|
||||
type="textarea"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
placeholder="请输入回复内容"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序">
|
||||
<div class="flex-1">
|
||||
<el-input-number v-model="formData.sort" :min="0" :max="9999" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="回复数量"
|
||||
prop="reply_num"
|
||||
required
|
||||
v-if="formData.reply_type == 2"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<el-radio-group v-model="formData.reply_num">
|
||||
<el-radio :value="1">回复匹配首词条</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="form-tips">
|
||||
设置关键词匹配多条时回复的数量,暂时支持回复一条内容
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用状态">
|
||||
<el-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</popup>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import type { FormRules } from 'element-plus'
|
||||
|
||||
import { getOaReplyDetail, oaReplyAdd, oaReplyEdit } from '@/api/channel/wx_oa'
|
||||
import Popup from '@/components/popup/index.vue'
|
||||
|
||||
const emit = defineEmits(['success', 'close'])
|
||||
|
||||
const formRef = shallowRef<FormInstance>()
|
||||
const popupRef = shallowRef<InstanceType<typeof Popup>>()
|
||||
const mode = ref('add')
|
||||
const popupTitle = computed(() => {
|
||||
return mode.value == 'edit' ? '编辑' : '新增'
|
||||
})
|
||||
const formData = reactive({
|
||||
id: '',
|
||||
name: '',
|
||||
reply_type: 0,
|
||||
content_type: 1,
|
||||
keyword: '',
|
||||
content: '',
|
||||
matching_type: 1,
|
||||
status: 1,
|
||||
sort: 0,
|
||||
reply_num: 1
|
||||
})
|
||||
|
||||
const formRules: FormRules = {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入规则名称',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
keyword: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入关键词',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
matching_type: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择匹配方式',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
content_type: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择回复类型',
|
||||
trigger: ['blur']
|
||||
}
|
||||
],
|
||||
content: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入回复内容',
|
||||
trigger: ['blur']
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
await formRef.value?.validate()
|
||||
mode.value == 'edit' ? await oaReplyEdit(formData) : await oaReplyAdd(formData)
|
||||
popupRef.value?.close()
|
||||
emit('success')
|
||||
}
|
||||
|
||||
const open = (modes = 'add', type = 0) => {
|
||||
mode.value = modes
|
||||
formData.reply_type = type
|
||||
popupRef.value?.open()
|
||||
}
|
||||
|
||||
const setFormData = (data: Record<any, any>) => {
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getDetail = async (row: Record<string, any>) => {
|
||||
const data = await getOaReplyDetail({
|
||||
id: row.id
|
||||
})
|
||||
setFormData(data)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
setFormData,
|
||||
getDetail
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:1.粉丝关注公众号时,会自动发送启用的关注回复;2.同时只能启用一个关注回复。"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div>
|
||||
<el-button class="mb-4" type="primary" @click="handleAdd()">
|
||||
<template #icon>
|
||||
<icon name="el-icon-Plus" />
|
||||
</template>
|
||||
新增
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table size="large" :data="pager.lists" v-loading="pager.loading">
|
||||
<el-table-column label="规则名称" prop="name" min-width="120" />
|
||||
<el-table-column label="回复类型" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{ getContentType(row.content_type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复内容" prop="content" min-width="120" />
|
||||
<el-table-column label="状态" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="changeStatus(row.id)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" prop="sort" min-width="120" />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
|
||||
<el-button type="danger" link @click="handleDelete(row.id)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="flex justify-end mt-4">
|
||||
<pagination v-model="pager" @change="getLists" />
|
||||
</div>
|
||||
</el-card>
|
||||
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { changeOaReplyStatus, getOaReplyList, oaReplyDel } from '@/api/channel/wx_oa'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
import EditPopup from './edit.vue'
|
||||
|
||||
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
|
||||
const showEdit = ref(false)
|
||||
|
||||
const getContentType = computed(() => {
|
||||
return (val: number) => {
|
||||
switch (val) {
|
||||
case 1:
|
||||
return '文本'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { pager, getLists } = usePaging({
|
||||
fetchFun: getOaReplyList,
|
||||
params: {
|
||||
reply_type: 1
|
||||
}
|
||||
})
|
||||
|
||||
const handleAdd = async () => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('add', 1)
|
||||
}
|
||||
|
||||
const handleEdit = async (data: any) => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('edit', 1)
|
||||
editRef.value?.getDetail(data)
|
||||
}
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
await feedback.confirm('确定要删除?')
|
||||
await oaReplyDel({ id })
|
||||
getLists()
|
||||
}
|
||||
|
||||
const changeStatus = async (id: number) => {
|
||||
try {
|
||||
await changeOaReplyStatus({ id })
|
||||
getLists()
|
||||
} catch (error) {
|
||||
getLists()
|
||||
}
|
||||
}
|
||||
|
||||
getLists()
|
||||
</script>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card class="!border-none" shadow="never">
|
||||
<el-alert
|
||||
type="warning"
|
||||
title="温馨提示:1.粉丝在公众号发送内容时,通过关键词可触发关键词回复;2.同时可启用多个关键词回复,有多条关键词匹配时优选选择排序靠前的一条"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-card>
|
||||
<el-card class="!border-none mt-4" shadow="never">
|
||||
<div>
|
||||
<el-button class="mb-4" type="primary" @click="handleAdd()">
|
||||
<template #icon>
|
||||
<icon name="el-icon-Plus" />
|
||||
</template>
|
||||
新增
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table size="large" :data="pager.lists" v-loading="pager.loading">
|
||||
<el-table-column label="规则名称" prop="name" min-width="120" />
|
||||
|
||||
<el-table-column label="关键词" prop="keyword" min-width="120" />
|
||||
<el-table-column label="匹配方式" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{ getMatchingType(row.matching_type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="回复类型" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{ getContentType(row.content_type) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-model="row.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="changeStatus(row.id)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序" prop="sort" min-width="120" />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)"> 编辑 </el-button>
|
||||
<el-button type="danger" link @click="handleDelete(row.id)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="flex justify-end mt-4">
|
||||
<pagination v-model="pager" @change="getLists" />
|
||||
</div>
|
||||
</el-card>
|
||||
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { changeOaReplyStatus, getOaReplyList, oaReplyDel } from '@/api/channel/wx_oa'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
import EditPopup from './edit.vue'
|
||||
|
||||
const editRef = shallowRef<InstanceType<typeof EditPopup>>()
|
||||
const showEdit = ref(false)
|
||||
|
||||
const getMatchingType = computed(() => {
|
||||
return (val: number) => {
|
||||
switch (val) {
|
||||
case 1:
|
||||
return '全匹配'
|
||||
case 2:
|
||||
return '模糊匹配'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const getContentType = computed(() => {
|
||||
return (val: number) => {
|
||||
switch (val) {
|
||||
case 1:
|
||||
return '文本'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { pager, getLists } = usePaging({
|
||||
fetchFun: getOaReplyList,
|
||||
params: {
|
||||
reply_type: 2
|
||||
}
|
||||
})
|
||||
const handleAdd = async () => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('add', 2)
|
||||
}
|
||||
|
||||
const handleEdit = async (data: any) => {
|
||||
showEdit.value = true
|
||||
await nextTick()
|
||||
editRef.value?.open('edit', 2)
|
||||
editRef.value?.getDetail(data)
|
||||
}
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
await feedback.confirm('确定要删除?')
|
||||
await oaReplyDel({ id })
|
||||
getLists()
|
||||
}
|
||||
|
||||
const changeStatus = async (id: number) => {
|
||||
try {
|
||||
await changeOaReplyStatus({ id })
|
||||
getLists()
|
||||
} catch (error) {
|
||||
getLists()
|
||||
}
|
||||
}
|
||||
|
||||
getLists()
|
||||
</script>
|
||||
Reference in New Issue
Block a user