This commit is contained in:
parent
521ae6e1ad
commit
2a0b910c7a
|
|
@ -91,3 +91,12 @@ export function resendOneLoopMsgAPI(data) {
|
|||
})
|
||||
}
|
||||
|
||||
// 立即执行一次
|
||||
export function runOneLoopMsgAPI(data) {
|
||||
return request({
|
||||
url: '/msgJob/executeOnceJob',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,34 +101,54 @@
|
|||
</el-table>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧已选人员 -->
|
||||
<!-- 右侧已选内容 -->
|
||||
<el-col :span="8">
|
||||
<div class="selected-persons">
|
||||
<div class="selected-header">
|
||||
<span>已选人员</span>
|
||||
<span>{{ activeTab === 'person' ? '已选人员' : '已选分组人员' }}</span>
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
@click="handleClearAll"
|
||||
:disabled="allSelectedPersons.length === 0"
|
||||
:disabled="
|
||||
activeTab === 'person'
|
||||
? directSelectedPersonIds.length === 0
|
||||
: selectedGroupIds.length === 0
|
||||
"
|
||||
>
|
||||
清空
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="selected-list">
|
||||
<div
|
||||
v-for="person in allSelectedPersons"
|
||||
:key="person.id"
|
||||
class="selected-item"
|
||||
>
|
||||
<span>{{ person.workerName }}</span>
|
||||
<el-icon class="remove-icon" @click="handleRemovePerson(person.id)">
|
||||
<Close />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div v-if="allSelectedPersons.length === 0" class="empty-tip">
|
||||
暂未选择人员
|
||||
</div>
|
||||
<!-- 人员tab:显示已选人员 -->
|
||||
<template v-if="activeTab === 'person'">
|
||||
<div
|
||||
v-for="person in directSelectedPersons"
|
||||
:key="person.id"
|
||||
class="selected-item"
|
||||
>
|
||||
<span>{{ person.workerName }}</span>
|
||||
<el-icon class="remove-icon" @click="handleRemovePerson(person.id)">
|
||||
<Close />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div v-if="directSelectedPersons.length === 0" class="empty-tip">
|
||||
暂未选择人员
|
||||
</div>
|
||||
</template>
|
||||
<!-- 分组tab:显示已选分组的所有人员 -->
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="person in groupSelectedPersons"
|
||||
:key="`${person.groupId}-${person.id}`"
|
||||
class="selected-item"
|
||||
>
|
||||
<span>{{ person.workerName }}</span>
|
||||
</div>
|
||||
<div v-if="groupSelectedPersons.length === 0" class="empty-tip">
|
||||
暂未选择分组
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
|
@ -147,9 +167,13 @@ const props = defineProps({
|
|||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
groupList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'confirm'])
|
||||
const emit = defineEmits(['update:modelValue', 'update:groupList', 'confirm'])
|
||||
|
||||
const activeTab = ref('person')
|
||||
const searchKeyword = ref('')
|
||||
|
|
@ -170,6 +194,9 @@ const selectedGroupIds = ref([])
|
|||
// 标志位:是否正在同步选中状态
|
||||
const isSyncing = ref(false)
|
||||
|
||||
// 标志位:是否已经初始化过(用于区分是用户操作还是外部数据变化)
|
||||
const isInitialized = ref(false)
|
||||
|
||||
// 过滤后的人员列表
|
||||
const filteredPersonList = computed(() => {
|
||||
if (!searchKeyword.value) {
|
||||
|
|
@ -190,7 +217,7 @@ const filteredGroupList = computed(() => {
|
|||
}
|
||||
const keyword = groupSearchKeyword.value.toLowerCase()
|
||||
return groupList.value.filter((item) => {
|
||||
const groupName = (item.groupName || '').toLowerCase()
|
||||
const groupName = (item.groupName || item.workerName || '').toLowerCase()
|
||||
return groupName.includes(keyword)
|
||||
})
|
||||
})
|
||||
|
|
@ -198,46 +225,46 @@ const filteredGroupList = computed(() => {
|
|||
// 选中的分组数量
|
||||
const selectedGroupCount = computed(() => selectedGroupIds.value.length)
|
||||
|
||||
// 所有已选人员(包括直接选择的人员和从分组中选择的人员)
|
||||
const allSelectedPersons = computed(() => {
|
||||
const personMap = new Map()
|
||||
// 直接选择的人员列表(用于人员tab显示)
|
||||
const directSelectedPersons = computed(() => {
|
||||
return directSelectedPersonIds.value
|
||||
.map((personId) => {
|
||||
const person = personList.value.find((p) => p.id === personId)
|
||||
if (person) {
|
||||
return {
|
||||
id: person.id,
|
||||
workerName: person.workerName,
|
||||
orgName: person.orgName,
|
||||
sex: person.sex,
|
||||
phone: person.phone,
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter(Boolean)
|
||||
})
|
||||
|
||||
// 添加直接选择的人员
|
||||
directSelectedPersonIds.value.forEach((personId) => {
|
||||
const person = personList.value.find((p) => p.id === personId)
|
||||
if (person) {
|
||||
personMap.set(person.id, {
|
||||
id: person.id,
|
||||
workerName: person.workerName,
|
||||
orgName: person.orgName,
|
||||
sex: person.sex,
|
||||
phone: person.phone,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 添加从分组中选择的人员(去重)
|
||||
// 从分组中选择的人员列表(用于分组tab显示,不去重)
|
||||
const groupSelectedPersons = computed(() => {
|
||||
const persons = []
|
||||
selectedGroupIds.value.forEach((groupId) => {
|
||||
const group = groupList.value.find((g) => g.id === groupId)
|
||||
if (group && group.workerList && Array.isArray(group.workerList)) {
|
||||
group.workerList.forEach((worker) => {
|
||||
if (worker && worker.id) {
|
||||
// 如果已存在,不覆盖(保持直接选择的数据)
|
||||
if (!personMap.has(worker.id)) {
|
||||
personMap.set(worker.id, {
|
||||
id: worker.id,
|
||||
workerName: worker.workerName || worker.name || '',
|
||||
orgName: worker.orgName || '',
|
||||
sex: worker.sex,
|
||||
phone: worker.phone || '',
|
||||
})
|
||||
}
|
||||
persons.push({
|
||||
id: worker.id,
|
||||
groupId: groupId,
|
||||
workerName: worker.workerName || worker.name || '',
|
||||
orgName: worker.orgName || '',
|
||||
sex: worker.sex,
|
||||
phone: worker.phone || '',
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return Array.from(personMap.values())
|
||||
return persons
|
||||
})
|
||||
|
||||
// 直接选择的人员数量
|
||||
|
|
@ -249,6 +276,7 @@ const selectedPersonCount = computed(() => {
|
|||
const handleTabChange = (tabName) => {
|
||||
searchKeyword.value = ''
|
||||
groupSearchKeyword.value = ''
|
||||
// 切换tab时,只同步当前tab的选中状态,不清空已选项
|
||||
nextTick(() => {
|
||||
if (tabName === 'person') {
|
||||
syncPersonTableSelection()
|
||||
|
|
@ -293,47 +321,37 @@ const onPersonSelectionChange = (selection) => {
|
|||
updateSelectedPersons()
|
||||
}
|
||||
|
||||
// 更新选中的所有人(合并直接选择的人员和分组中的人员)
|
||||
// 更新选中的内容
|
||||
const updateSelectedPersons = () => {
|
||||
const personMap = new Map()
|
||||
// 标记为已初始化,避免watch反向同步
|
||||
isInitialized.value = true
|
||||
|
||||
// 添加直接选择的人员
|
||||
directSelectedPersonIds.value.forEach((personId) => {
|
||||
const person = personList.value.find((p) => p.id === personId)
|
||||
if (person) {
|
||||
personMap.set(person.id, {
|
||||
id: person.id,
|
||||
workerName: person.workerName,
|
||||
orgName: person.orgName,
|
||||
sex: person.sex,
|
||||
phone: person.phone,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 添加从分组中选择的人员(去重)
|
||||
selectedGroupIds.value.forEach((groupId) => {
|
||||
const group = groupList.value.find((g) => g.id === groupId)
|
||||
if (group && group.workerList && Array.isArray(group.workerList)) {
|
||||
group.workerList.forEach((worker) => {
|
||||
if (worker && worker.id) {
|
||||
// 如果已存在,不覆盖(保持直接选择的数据)
|
||||
if (!personMap.has(worker.id)) {
|
||||
personMap.set(worker.id, {
|
||||
id: worker.id,
|
||||
workerName: worker.workerName || worker.name || '',
|
||||
orgName: worker.orgName || '',
|
||||
sex: worker.sex,
|
||||
phone: worker.phone || '',
|
||||
})
|
||||
}
|
||||
// 更新人员列表
|
||||
const persons = directSelectedPersonIds.value
|
||||
.map((personId) => {
|
||||
const person = personList.value.find((p) => p.id === personId)
|
||||
if (person) {
|
||||
return {
|
||||
id: person.id,
|
||||
workerName: person.workerName,
|
||||
orgName: person.orgName,
|
||||
sex: person.sex,
|
||||
phone: person.phone,
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter(Boolean)
|
||||
emit('update:modelValue', persons)
|
||||
|
||||
// 触发更新事件
|
||||
emit('update:modelValue', Array.from(personMap.values()))
|
||||
// 更新分组列表
|
||||
const groups = selectedGroupIds.value
|
||||
.map((groupId) => {
|
||||
const group = groupList.value.find((g) => g.id === groupId)
|
||||
return group ? { id: group.id, groupName: group.groupName || group.workerName } : null
|
||||
})
|
||||
.filter(Boolean)
|
||||
emit('update:groupList', groups)
|
||||
}
|
||||
|
||||
// 分组选择变化
|
||||
|
|
@ -354,7 +372,7 @@ const onGroupSelectionChange = (selection) => {
|
|||
// 合并保留的ID和当前选中的可见ID
|
||||
selectedGroupIds.value = [...preservedIds, ...selectedVisibleIds]
|
||||
|
||||
// 触发更新,合并所有选中的人员
|
||||
// 触发更新,传递分组列表
|
||||
updateSelectedPersons()
|
||||
}
|
||||
|
||||
|
|
@ -418,40 +436,10 @@ const syncGroupTableSelection = () => {
|
|||
})
|
||||
}
|
||||
|
||||
// 移除单个人员
|
||||
// 移除单个人员(仅用于人员tab)
|
||||
const handleRemovePerson = (personId) => {
|
||||
// 检查该人员是否在直接选择列表中
|
||||
const isDirectSelected = directSelectedPersonIds.value.includes(personId)
|
||||
|
||||
// 检查该人员是否来自分组
|
||||
const groupsContainingPerson = []
|
||||
selectedGroupIds.value.forEach((groupId) => {
|
||||
const group = groupList.value.find((g) => g.id === groupId)
|
||||
if (group && group.workerList && Array.isArray(group.workerList)) {
|
||||
const hasPerson = group.workerList.some((w) => w.id === personId)
|
||||
if (hasPerson) {
|
||||
groupsContainingPerson.push(groupId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 如果人员既在直接选择列表中,又在分组中,只移除直接选择,保留分组
|
||||
if (isDirectSelected) {
|
||||
directSelectedPersonIds.value = directSelectedPersonIds.value.filter(
|
||||
(id) => id !== personId,
|
||||
)
|
||||
} else if (groupsContainingPerson.length > 0) {
|
||||
// 如果人员只来自分组(不在直接选择列表中),移除对应的分组
|
||||
selectedGroupIds.value = selectedGroupIds.value.filter(
|
||||
(id) => !groupsContainingPerson.includes(id),
|
||||
)
|
||||
nextTick(() => {
|
||||
syncGroupTableSelection()
|
||||
})
|
||||
}
|
||||
|
||||
directSelectedPersonIds.value = directSelectedPersonIds.value.filter((id) => id !== personId)
|
||||
updateSelectedPersons()
|
||||
|
||||
// 同步人员表格
|
||||
nextTick(() => {
|
||||
syncPersonTableSelection()
|
||||
|
|
@ -461,15 +449,18 @@ const handleRemovePerson = (personId) => {
|
|||
// 清空所有选择
|
||||
const handleClearAll = () => {
|
||||
isSyncing.value = true
|
||||
directSelectedPersonIds.value = []
|
||||
selectedGroupIds.value = []
|
||||
emit('update:modelValue', [])
|
||||
if (personTableRef.value) {
|
||||
personTableRef.value.clearSelection()
|
||||
}
|
||||
if (groupTableRef.value) {
|
||||
groupTableRef.value.clearSelection()
|
||||
if (activeTab.value === 'person') {
|
||||
directSelectedPersonIds.value = []
|
||||
if (personTableRef.value) {
|
||||
personTableRef.value.clearSelection()
|
||||
}
|
||||
} else {
|
||||
selectedGroupIds.value = []
|
||||
if (groupTableRef.value) {
|
||||
groupTableRef.value.clearSelection()
|
||||
}
|
||||
}
|
||||
updateSelectedPersons()
|
||||
nextTick(() => {
|
||||
isSyncing.value = false
|
||||
})
|
||||
|
|
@ -495,7 +486,11 @@ const getGroupList = async () => {
|
|||
try {
|
||||
const result = await getAllGroupAPI()
|
||||
if (result.code === 200 && result.rows) {
|
||||
groupList.value = result.rows || []
|
||||
// 统一分组数据格式:将 workerName 转换为 groupName
|
||||
groupList.value = (result.rows || []).map((group) => ({
|
||||
...group,
|
||||
groupName: group.groupName || group.workerName || '',
|
||||
}))
|
||||
nextTick(() => {
|
||||
syncGroupTableSelection()
|
||||
})
|
||||
|
|
@ -505,37 +500,99 @@ const getGroupList = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// 监听 modelValue 变化,仅在初始化时同步(避免干扰用户操作)
|
||||
// 监听 modelValue 变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
// 如果内部状态已经有数据,说明是用户操作导致的,不需要反向同步
|
||||
// 只在初始化时(两个列表都为空)才同步
|
||||
if (directSelectedPersonIds.value.length > 0 || selectedGroupIds.value.length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!newVal || newVal.length === 0) {
|
||||
directSelectedPersonIds.value = []
|
||||
// 如果外部数据为空,且内部状态也为空,则不需要处理
|
||||
if (directSelectedPersonIds.value.length === 0) {
|
||||
return
|
||||
}
|
||||
// 如果外部数据为空,但内部状态有值,且未初始化过,则清空
|
||||
if (!isInitialized.value) {
|
||||
directSelectedPersonIds.value = []
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 初始化时,尝试区分哪些是直接选择的人员
|
||||
// 由于此时还没有分组数据,先假设所有人员都是直接选择的
|
||||
// 等分组数据加载后,会通过 updateSelectedPersons 重新计算
|
||||
const personIds = newVal.map((p) => p.id).filter(Boolean)
|
||||
directSelectedPersonIds.value = personIds
|
||||
// 获取外部传入的人员ID列表
|
||||
const externalPersonIds = newVal.map((p) => p.id).filter(Boolean)
|
||||
|
||||
if (activeTab.value === 'person') {
|
||||
nextTick(() => {
|
||||
syncPersonTableSelection()
|
||||
})
|
||||
// 如果外部数据与内部状态一致,不需要更新
|
||||
const currentIds = new Set(directSelectedPersonIds.value.map((id) => Number(id)))
|
||||
const externalIds = new Set(externalPersonIds.map((id) => Number(id)))
|
||||
const isEqual =
|
||||
currentIds.size === externalIds.size &&
|
||||
[...currentIds].every((id) => externalIds.has(id))
|
||||
|
||||
if (isEqual && isInitialized.value) {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新选中的人员ID(仅在未初始化或外部数据变化时)
|
||||
if (!isInitialized.value || !isEqual) {
|
||||
directSelectedPersonIds.value = externalPersonIds
|
||||
isInitialized.value = true
|
||||
|
||||
if (activeTab.value === 'person') {
|
||||
nextTick(() => {
|
||||
syncPersonTableSelection()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
)
|
||||
|
||||
// 监听 groupList 变化
|
||||
watch(
|
||||
() => props.groupList,
|
||||
(newVal) => {
|
||||
if (!newVal || newVal.length === 0) {
|
||||
// 如果外部数据为空,且内部状态也为空,则不需要处理
|
||||
if (selectedGroupIds.value.length === 0) {
|
||||
return
|
||||
}
|
||||
// 如果外部数据为空,但内部状态有值,且未初始化过,则清空
|
||||
if (!isInitialized.value) {
|
||||
selectedGroupIds.value = []
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取外部传入的分组ID列表
|
||||
const externalGroupIds = newVal.map((g) => g.id).filter(Boolean)
|
||||
|
||||
// 如果外部数据与内部状态一致,不需要更新
|
||||
const currentIds = new Set(selectedGroupIds.value.map((id) => Number(id)))
|
||||
const externalIds = new Set(externalGroupIds.map((id) => Number(id)))
|
||||
const isEqual =
|
||||
currentIds.size === externalIds.size &&
|
||||
[...currentIds].every((id) => externalIds.has(id))
|
||||
|
||||
if (isEqual && isInitialized.value) {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新选中的分组ID(仅在未初始化或外部数据变化时)
|
||||
if (!isInitialized.value || !isEqual) {
|
||||
selectedGroupIds.value = externalGroupIds
|
||||
isInitialized.value = true
|
||||
|
||||
if (activeTab.value === 'group') {
|
||||
nextTick(() => {
|
||||
syncGroupTableSelection()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
// 重置初始化标志,确保能正确同步外部传入的数据
|
||||
isInitialized.value = false
|
||||
getPersonList()
|
||||
getGroupList()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -33,14 +33,21 @@
|
|||
</template>
|
||||
|
||||
<script setup name="Index">
|
||||
import { ref } from 'vue'
|
||||
import { ref, markRaw } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Message, Bell, Document, Setting, DataAnalysis, Connection } from '@element-plus/icons-vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 装饰性图标列表
|
||||
const icons = ref([Message, Bell, Document, Setting, DataAnalysis, Connection])
|
||||
// 装饰性图标列表 - 使用 markRaw 避免组件被响应式化
|
||||
const icons = ref([
|
||||
markRaw(Message),
|
||||
markRaw(Bell),
|
||||
markRaw(Document),
|
||||
markRaw(Setting),
|
||||
markRaw(DataAnalysis),
|
||||
markRaw(Connection),
|
||||
])
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ export const tableColumns = [
|
|||
label: '任务状态',
|
||||
slot: 'taskStatus',
|
||||
},
|
||||
{
|
||||
prop: 'remark',
|
||||
label: '备注',
|
||||
},
|
||||
]
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -10,21 +10,21 @@
|
|||
</template>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="!isDetail ? rules : {}"
|
||||
size="large"
|
||||
:model="formData"
|
||||
label-width="auto"
|
||||
:disabled="isDetail"
|
||||
:rules="!isDetail ? rules : {}"
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务名称" prop="taskName">
|
||||
<el-input
|
||||
v-model.trim="formData.taskName"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
clearable
|
||||
placeholder="请输入任务名称"
|
||||
v-model.trim="formData.taskName"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -32,10 +32,10 @@
|
|||
<el-col :span="12">
|
||||
<el-form-item label="短信类型" prop="msgType">
|
||||
<el-select
|
||||
v-model="formData.msgType"
|
||||
placeholder="请选择短信类型"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
v-model="formData.msgType"
|
||||
placeholder="请选择短信类型"
|
||||
>
|
||||
<el-option label="通知" value="1" />
|
||||
<el-option label="计划" value="2" />
|
||||
|
|
@ -77,26 +77,26 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<!-- <el-col :span="12">
|
||||
<el-form-item label="是否并发" prop="concurrent">
|
||||
<el-radio-group v-model="formData.concurrent">
|
||||
<el-radio-button value="0">允许</el-radio-button>
|
||||
<el-radio-button value="1">禁止</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="发送内容" prop="sendContent">
|
||||
<el-input
|
||||
v-model.trim="formData.sendContent"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="请输入发送内容"
|
||||
type="textarea"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="请输入发送内容"
|
||||
v-model.trim="formData.sendContent"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -106,12 +106,12 @@
|
|||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model.trim="formData.remark"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
placeholder="请输入备注"
|
||||
maxlength="500"
|
||||
type="textarea"
|
||||
show-word-limit
|
||||
placeholder="请输入备注"
|
||||
v-model.trim="formData.remark"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -136,30 +136,41 @@
|
|||
<el-form-item label="接收人员" prop="recipientList">
|
||||
<div class="recipient-select">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
icon="Plus"
|
||||
@click="onOpenPersonPicker"
|
||||
:disabled="isDetail"
|
||||
type="primary"
|
||||
v-if="!isDetail"
|
||||
:disabled="isDetail"
|
||||
@click="onOpenPersonPicker"
|
||||
>
|
||||
选择
|
||||
</el-button>
|
||||
<span class="selected-names">{{ selectedRecipientNames }}</span>
|
||||
</div>
|
||||
<el-table
|
||||
v-if="formData.recipientList && formData.recipientList.length > 0"
|
||||
:data="formData.recipientList"
|
||||
border
|
||||
style="margin-top: 10px"
|
||||
v-if="formData.recipientList && formData.recipientList.length > 0"
|
||||
>
|
||||
<el-table-column
|
||||
width="80"
|
||||
type="index"
|
||||
label="序号"
|
||||
align="center"
|
||||
:data="formData.recipientList"
|
||||
/>
|
||||
<el-table-column align="center" prop="workerName" label="姓名" />
|
||||
<el-table-column align="center" prop="phone" label="电话" />
|
||||
<el-table-column v-if="!isDetail" label="操作" align="center">
|
||||
<el-table-column
|
||||
width="140"
|
||||
label="操作"
|
||||
align="center"
|
||||
v-if="!isDetail"
|
||||
>
|
||||
<template #default="{ $index }">
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
@click="handleRemoveRecipient($index)"
|
||||
>
|
||||
|
|
@ -172,10 +183,52 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24" v-if="isGenderSendGroup === 0">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="已选分组">
|
||||
<el-table
|
||||
border
|
||||
style="margin-top: 10px"
|
||||
:data="formData.groupList"
|
||||
v-if="formData.groupList && formData.groupList.length > 0"
|
||||
>
|
||||
<el-table-column
|
||||
width="80"
|
||||
type="index"
|
||||
label="序号"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column align="center" prop="groupName" label="分组名称" />
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="140"
|
||||
align="center"
|
||||
v-if="!isDetail"
|
||||
>
|
||||
<template #default="{ $index }">
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
@click="handleRemoveGroup($index)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-else class="recipient-select">
|
||||
<span class="selected-names">暂未选择分组</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24" v-if="isGenderSendGroup === 1">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="群发短信群体" prop="genderSendGroup">
|
||||
<el-radio-group v-model="formData.genderSendGroup">
|
||||
<el-form-item label="群发短信群体" prop="sex">
|
||||
<el-radio-group v-model="formData.sex">
|
||||
<el-radio-button :value="1">男</el-radio-button>
|
||||
<el-radio-button :value="0">女</el-radio-button>
|
||||
</el-radio-group>
|
||||
|
|
@ -198,8 +251,8 @@
|
|||
<template #outerContent>
|
||||
<crontab
|
||||
ref="crontabRef"
|
||||
@hide="handleCronHide"
|
||||
@fill="crontabFill"
|
||||
@hide="handleCronHide"
|
||||
:expression="cronExpression"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -208,7 +261,12 @@
|
|||
<!-- 人员选择弹窗 -->
|
||||
<ComDialog :dialog-config="managerDialogConfig" @closeDialogOuter="onCloseDialogOuter">
|
||||
<template #outerContent>
|
||||
<PersonPicker v-model="formData.recipientList" />
|
||||
<PersonPicker
|
||||
v-model="formData.recipientList"
|
||||
:group-list="formData.groupList"
|
||||
@update:groupList="handleGroupListUpdate"
|
||||
:key="`picker-${managerDialogConfig.outerVisible}`"
|
||||
/>
|
||||
<el-row class="common-btn-row fixed-bottom">
|
||||
<ComButton plain type="info" @click="managerDialogConfig.outerVisible = false">
|
||||
取消
|
||||
|
|
@ -251,19 +309,19 @@ const pageTitle = computed(() => {
|
|||
})
|
||||
|
||||
const formRef = ref(null)
|
||||
const crontabRef = ref(null)
|
||||
const personTableRef = ref(null)
|
||||
const cronExpression = ref('')
|
||||
const taskStatus = ref('')
|
||||
const crontabRef = ref(null)
|
||||
const cronExpression = ref('')
|
||||
const personTableRef = ref(null)
|
||||
const isGenderSendGroup = ref(0)
|
||||
|
||||
// Cron表达式生成器弹窗配置
|
||||
const cronDialogConfig = reactive({
|
||||
maxHeight: '80vh',
|
||||
minHeight: '500px',
|
||||
outerWidth: '70%',
|
||||
outerVisible: false,
|
||||
outerTitle: 'Cron表达式生成器',
|
||||
outerWidth: '70%',
|
||||
minHeight: '500px',
|
||||
maxHeight: '80vh',
|
||||
})
|
||||
|
||||
// 定义初始表单数据
|
||||
|
|
@ -275,8 +333,9 @@ const getInitFormData = () => ({
|
|||
misfirePolicy: '1', // 执行策略:1-立即执行,2-执行一次,3-放弃执行
|
||||
concurrent: '1', // 是否并发:0-允许,1-禁止
|
||||
sendContent: '', // 发送内容
|
||||
genderSendGroup: '', // 群发短信群体:0-男,1-女
|
||||
sex: '', // 群发短信群体:0-男,1-女
|
||||
recipientList: [], // 接收人员列表
|
||||
groupList: [], // 接收分组列表
|
||||
})
|
||||
|
||||
const formData = ref(getInitFormData())
|
||||
|
|
@ -290,18 +349,24 @@ const rules = {
|
|||
recipientList: [
|
||||
{
|
||||
required: true,
|
||||
message: '请至少选择一个接收人员',
|
||||
message: '请至少选择一个接收人员或分组',
|
||||
trigger: 'change',
|
||||
validator: (rule, value, callback) => {
|
||||
// 如果选择了分组,则不需要验证人员列表
|
||||
if (formData.value.groupList && formData.value.groupList.length > 0) {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
// 如果没有选择分组,则必须选择人员
|
||||
if (!value || value.length === 0) {
|
||||
callback(new Error('请至少选择一个接收人员'))
|
||||
callback(new Error('请至少选择一个接收人员或分组'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
genderSendGroup: [{ required: true, message: '请选择群发短信群体', trigger: 'change' }],
|
||||
sex: [{ required: true, message: '请选择群发短信群体', trigger: 'change' }],
|
||||
}
|
||||
|
||||
// 人员选择弹窗相关
|
||||
|
|
@ -321,6 +386,11 @@ const selectedRecipientNames = computed(() => {
|
|||
return formData.value.recipientList.map((item) => item.workerName).join('、')
|
||||
})
|
||||
|
||||
// 处理分组列表更新
|
||||
const handleGroupListUpdate = (groupList) => {
|
||||
formData.value.groupList = groupList || []
|
||||
}
|
||||
|
||||
// 打开人员选择弹窗
|
||||
const onOpenPersonPicker = () => {
|
||||
managerDialogConfig.outerVisible = true
|
||||
|
|
@ -336,6 +406,10 @@ const handleRemoveRecipient = (index) => {
|
|||
formData.value.recipientList.splice(index, 1)
|
||||
}
|
||||
|
||||
// 移除分组
|
||||
const handleRemoveGroup = (index) => {
|
||||
formData.value.groupList.splice(index, 1)
|
||||
}
|
||||
// 关闭人员选择弹窗
|
||||
const onCloseDialogOuter = (visible) => {
|
||||
managerDialogConfig.outerVisible = visible
|
||||
|
|
@ -386,11 +460,26 @@ const onSubmit = async () => {
|
|||
misfirePolicy: formData.value.misfirePolicy,
|
||||
concurrent: formData.value.concurrent,
|
||||
sendContent: formData.value.sendContent,
|
||||
workerList: formData.value.recipientList.map((item) => {
|
||||
sex: formData.value.sex,
|
||||
}
|
||||
|
||||
// 根据是否有分组列表来决定传递workerList还是groupList
|
||||
if (formData.value.groupList && formData.value.groupList.length > 0) {
|
||||
// 如果选择了分组,传递分组ID列表
|
||||
params.groupList = formData.value.groupList.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
if (formData.value.recipientList && formData.value.recipientList.length > 0) {
|
||||
// 如果选择了分组,传递分组ID列表
|
||||
params.workerList = formData.value.recipientList.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑时需要传递id
|
||||
|
|
@ -419,6 +508,13 @@ const getDetail = async () => {
|
|||
const result = await getLoopSendDetailAPI(route.query.id)
|
||||
if (result.code === 200 && result.data) {
|
||||
const data = result.data
|
||||
|
||||
// 处理分组列表:将后端返回的 workerName 字段转换为 groupName
|
||||
const groupList = (data.groupList || []).map((group) => ({
|
||||
id: group.id,
|
||||
groupName: group.workerName || group.groupName || '',
|
||||
}))
|
||||
|
||||
formData.value = {
|
||||
id: data.id,
|
||||
taskName: data.taskName || '',
|
||||
|
|
@ -428,7 +524,13 @@ const getDetail = async () => {
|
|||
concurrent: String(data.concurrent || '1'),
|
||||
sendContent: data.sendContent || '',
|
||||
recipientList: data.workerList || [],
|
||||
groupList: groupList,
|
||||
remark: data.remark || '',
|
||||
sex: data.sex || '',
|
||||
}
|
||||
|
||||
if (data.sex === 1 || data.sex === 0) {
|
||||
isGenderSendGroup.value = 1
|
||||
}
|
||||
taskStatus.value = data.taskStatus || ''
|
||||
cronExpression.value = data.cronExpression || ''
|
||||
|
|
@ -450,12 +552,12 @@ const onHandleDetail = async (row) => {
|
|||
|
||||
// 群发短信群体变化
|
||||
const handleGenderSendGroupChange = (value) => {
|
||||
console.log(value, 'value')
|
||||
|
||||
if (value === 0) {
|
||||
// 重置人员和分组列表
|
||||
formData.value.recipientList = []
|
||||
formData.value.groupList = []
|
||||
} else {
|
||||
formData.value.genderSendGroup = null
|
||||
formData.value.sex = ''
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -539,6 +641,12 @@ onMounted(() => {
|
|||
}
|
||||
}
|
||||
|
||||
.no-group-tip {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.person-search-bar {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ import {
|
|||
delLoopSendAPI,
|
||||
listLoopSendAPI,
|
||||
getSmsBalanceAPI,
|
||||
runOneLoopMsgAPI,
|
||||
updateLoopSendStatusAPI,
|
||||
} from '@/api/sMsSendManage/loopSend.js'
|
||||
import config from './config'
|
||||
|
|
@ -100,13 +101,20 @@ const actionColumns = [
|
|||
},
|
||||
|
||||
{
|
||||
label: '发送详情',
|
||||
label: '立即执行一次',
|
||||
type: 'primary',
|
||||
link: true,
|
||||
handler: (row) => {
|
||||
sendDetailsDialogConfig.outerTitle = `发送详情 - ${row.taskName || ''}`
|
||||
sendDetailsId.value = row.id
|
||||
sendDetailsDialogConfig.outerVisible = true
|
||||
runOneLoopMsgAPI({ id: row.id, jobId: row.jobId })
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
proxy.$modal.msgSuccess('执行成功')
|
||||
comTableRef.value?.refresh()
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
proxy.$modal.msgError('执行失败')
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -139,6 +147,16 @@ const actionColumns = [
|
|||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '发送详情',
|
||||
type: 'primary',
|
||||
link: true,
|
||||
handler: (row) => {
|
||||
sendDetailsDialogConfig.outerTitle = `发送详情 - ${row.taskName || ''}`
|
||||
sendDetailsId.value = row.id
|
||||
sendDetailsDialogConfig.outerVisible = true
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
// 新增
|
||||
|
|
|
|||
Loading…
Reference in New Issue