需求改了好多,不需要自己输用户名和qq号了
This commit is contained in:
parent
c40638eca2
commit
66efa6c310
@ -99,3 +99,17 @@ export const addDemandReply = async (id, replyData) => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取所有需求列表(管理员)
|
||||
* @returns {Promise<Array<Object>>} 返回所有需求列表数据
|
||||
*/
|
||||
export const getAllDemandsList = async () => {
|
||||
try {
|
||||
const response = await axiosInstance.get('/demands/getlistall');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('获取所有需求列表失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
@ -50,15 +50,27 @@
|
||||
<td class="date" data-label="创建时间">{{ formatDate(demand.date) }}</td>
|
||||
<td class="reply-count" data-label="回复数量">{{ getReplyCount(demand.sendcontent) }}</td>
|
||||
<td class="status" data-label="状态">
|
||||
<span :class="['tag', isDeleted(demand.content) ? 'deleted' : 'active']">
|
||||
{{ isDeleted(demand.content) ? '已删除' : '正常' }}
|
||||
<span :class="['tag', getStatusClass(demand)]">
|
||||
{{ getStatusText(demand) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="actions" data-label="操作">
|
||||
<button class="btn-common btn-small btn-gradient" @click="showDetail(demand)">查看</button>
|
||||
<button v-if="!isDeleted(demand.content)" class="btn-common btn-small btn-warning" @click="handleHide(demand)">隐藏</button>
|
||||
<button v-else class="btn-common btn-small btn-restore" @click="handleRestore(demand)">恢复</button>
|
||||
<button v-if="showDeletedItems" class="btn-common btn-small btn-danger" @click="handleDelete(demand)">删除</button>
|
||||
<!-- 检查是否为已删除状态 -->
|
||||
<template v-if="isDeleted(demand)">
|
||||
<!-- 已删除的需求:只有在显示已删除时才显示恢复按钮 -->
|
||||
<button v-if="showDeletedItems" class="btn-common btn-small btn-restore" @click="handleRestore(demand)">恢复</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<!-- 正常状态的需求:根据格式显示对应按钮 -->
|
||||
<template v-if="demand.status">
|
||||
<!-- 新格式数据 -->
|
||||
<button v-if="demand.status === 'NORMAL'" class="btn-common btn-small btn-warning" @click="handleHide(demand)">隐藏</button>
|
||||
<button v-if="demand.status === 'NORMAL' && showDeletedItems" class="btn-common btn-small btn-danger" @click="handleDelete(demand)">删除</button>
|
||||
<button v-if="demand.status === 'HIDE'" class="btn-common btn-small btn-restore" @click="handleRestore(demand)">恢复</button>
|
||||
</template>
|
||||
<!-- 旧格式数据:不显示任何操作按钮 -->
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -99,23 +111,27 @@
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<span class="label">状态:</span>
|
||||
<span :class="['tag', isDeleted(selectedDemand?.content) ? 'deleted' : 'active']">
|
||||
{{ isDeleted(selectedDemand?.content) ? '已删除' : '正常' }}
|
||||
<span :class="['tag', getStatusClass(selectedDemand)]">
|
||||
{{ getStatusText(selectedDemand) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="reply-section">
|
||||
<h3>回复内容</h3>
|
||||
<div class="reply-list">
|
||||
<div v-if="selectedDemand?.sendcontent">
|
||||
<div v-for="(reply, index) in selectedDemand.sendcontent.split('|')" :key="index" class="reply-content">
|
||||
<div v-if="selectedDemand?.sendcontent && replyParsedTexts.length > 0">
|
||||
<div v-for="(parsedReply, index) in replyParsedTexts" :key="index" class="reply-content">
|
||||
<div class="reply-with-avatar">
|
||||
<img :src="`https://q1.qlogo.cn/g?b=qq&nk=${extractQQ(reply)}&s=40`" alt="User Avatar" class="reply-avatar" />
|
||||
<img :src="`https://q1.qlogo.cn/g?b=qq&nk=${extractQQ(selectedDemand.sendcontent.split('|')[index])}&s=40`" alt="User Avatar" class="reply-avatar" />
|
||||
<div class="reply-text">
|
||||
<b>{{ parseReplyText(reply).user }}</b> {{ parseReplyText(reply).content }}
|
||||
<b>{{ parsedReply.user }}</b>
|
||||
<span class="reply-content-with-newlines">{{ parsedReply.content }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="selectedDemand?.sendcontent && replyParsedTexts.length === 0">
|
||||
加载中...
|
||||
</div>
|
||||
<div v-else class="no-reply">
|
||||
暂无回复
|
||||
</div>
|
||||
@ -201,7 +217,9 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { getDemandsList, updateDemand, deleteDemand, addDemand } from '../../api/demands'
|
||||
import { getAllDemandsList, updateDemand, deleteDemand, addDemand, getDemandsList } from '../../api/demands'
|
||||
import { getUserByInfo } from '../../api/login'
|
||||
import { getStoredUser } from '@/utils/jwt'
|
||||
|
||||
// 响应式数据
|
||||
const demands = ref([])
|
||||
@ -209,6 +227,8 @@ const loading = ref(false)
|
||||
const error = ref(null)
|
||||
const showModal = ref(false)
|
||||
const selectedDemand = ref(null)
|
||||
const replyParsedTexts = ref([])
|
||||
const usernameCache = ref({})
|
||||
const showDeleteConfirm = ref(false)
|
||||
const showRestoreConfirm = ref(false)
|
||||
const pendingDeleteId = ref(null)
|
||||
@ -225,12 +245,25 @@ const addForm = ref({
|
||||
const addError = ref('')
|
||||
const addLoading = ref(false)
|
||||
|
||||
// 判断是否已删除(兼容新旧格式)
|
||||
const isDeleted = (demand) => {
|
||||
// 优先检查旧格式:content是否以&DEL开头
|
||||
if (demand.content?.startsWith('&DEL')) {
|
||||
return true
|
||||
}
|
||||
// 检查新格式:status字段
|
||||
if (demand.status === 'DEL') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 计算属性:根据显示设置过滤需求
|
||||
const displayDemands = computed(() => {
|
||||
if (showDeletedItems.value) {
|
||||
return demands.value
|
||||
} else {
|
||||
return demands.value.filter(demand => !isDeleted(demand.content))
|
||||
return demands.value.filter(demand => !isDeleted(demand))
|
||||
}
|
||||
})
|
||||
|
||||
@ -239,17 +272,77 @@ const isNoReward = (reward) => {
|
||||
return !reward || reward === '无赏金'
|
||||
}
|
||||
|
||||
// 判断是否已删除
|
||||
const isDeleted = (content) => {
|
||||
return content?.startsWith('&DEL')
|
||||
// 获取状态样式类
|
||||
const getStatusClass = (demand) => {
|
||||
// 兼容旧格式:优先检查content是否以&DEL开头
|
||||
if (demand.content?.startsWith('&DEL')) {
|
||||
return 'status-deleted'
|
||||
}
|
||||
// 新格式:使用status字段
|
||||
if (demand.status) {
|
||||
switch (demand.status) {
|
||||
case 'NORMAL':
|
||||
return 'status-normal'
|
||||
case 'DEL':
|
||||
return 'status-deleted'
|
||||
case 'HIDE':
|
||||
return 'status-hidden'
|
||||
default:
|
||||
return 'status-normal'
|
||||
}
|
||||
}
|
||||
return 'status-normal'
|
||||
}
|
||||
|
||||
// 获取显示内容(去掉删除标记)
|
||||
// 获取状态显示文本
|
||||
const getStatusText = (demand) => {
|
||||
// 兼容旧格式:优先检查content是否以&DEL开头
|
||||
if (demand.content?.startsWith('&DEL')) {
|
||||
return '已删除'
|
||||
}
|
||||
// 新格式:使用status字段
|
||||
if (demand.status) {
|
||||
switch (demand.status) {
|
||||
case 'NORMAL':
|
||||
return '正常'
|
||||
case 'DEL':
|
||||
return '已删除'
|
||||
case 'HIDE':
|
||||
return '已隐藏'
|
||||
default:
|
||||
return '正常'
|
||||
}
|
||||
}
|
||||
return '正常'
|
||||
}
|
||||
|
||||
// 获取显示内容
|
||||
const getDisplayContent = (content) => {
|
||||
if (!content) return ''
|
||||
// 兼容旧格式:去掉&DEL标记
|
||||
return content.replace(/^&DEL/, '')
|
||||
}
|
||||
|
||||
// 判断是否为正常状态
|
||||
const isNormalStatus = (demand) => {
|
||||
// 新格式:检查status字段
|
||||
if (demand.status) {
|
||||
return demand.status === 'NORMAL'
|
||||
}
|
||||
// 兼容旧格式:content不以&DEL开头
|
||||
return !demand.content?.startsWith('&DEL')
|
||||
}
|
||||
|
||||
// 判断是否为隐藏状态
|
||||
const isHiddenStatus = (demand) => {
|
||||
// 新格式:检查status字段
|
||||
if (demand.status) {
|
||||
return demand.status === 'HIDE'
|
||||
}
|
||||
// 旧格式没有隐藏状态,只返回false
|
||||
return false
|
||||
}
|
||||
|
||||
// 获取回复数量
|
||||
const getReplyCount = (sendcontent) => {
|
||||
if (!sendcontent) return 0
|
||||
@ -278,8 +371,14 @@ const fetchDemands = async () => {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
try {
|
||||
const data = await getDemandsList()
|
||||
const data = await getAllDemandsList()
|
||||
demands.value = data
|
||||
|
||||
// 输出当前用户信息用于调试
|
||||
const currentUser = getStoredUser()
|
||||
console.log('当前用户信息:', currentUser)
|
||||
console.log('用户权限:', currentUser?.privilege)
|
||||
console.log('临时权限:', currentUser?.temp_privilege)
|
||||
} catch (err) {
|
||||
console.error('加载需求列表失败:', err)
|
||||
if (err.response?.status === 403) {
|
||||
@ -295,9 +394,19 @@ const fetchDemands = async () => {
|
||||
}
|
||||
|
||||
// 显示详情弹窗
|
||||
const showDetail = (demand) => {
|
||||
const showDetail = async (demand) => {
|
||||
selectedDemand.value = demand
|
||||
showModal.value = true
|
||||
|
||||
// 如果有sendcontent,解析所有回复文本
|
||||
if (demand.sendcontent) {
|
||||
replyParsedTexts.value = []
|
||||
const replies = demand.sendcontent.split('|')
|
||||
for (let i = 0; i < replies.length; i++) {
|
||||
const parsed = await parseReplyText(replies[i])
|
||||
replyParsedTexts.value[i] = parsed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
@ -316,25 +425,35 @@ const handleHide = (demand) => {
|
||||
// 确认操作
|
||||
const confirmOperation = async () => {
|
||||
try {
|
||||
if (currentOperation.value === 'hide') {
|
||||
const demand = demands.value.find(d => d.id === pendingDeleteId.value)
|
||||
if (!demand) return
|
||||
const demand = demands.value.find(d => d.id === pendingDeleteId.value)
|
||||
if (!demand) return
|
||||
|
||||
const updatedContent = `&DEL${demand.content}`
|
||||
await updateDemand(pendingDeleteId.value, {
|
||||
requester: demand.requester,
|
||||
qq_code: demand.qq_code,
|
||||
content: updatedContent,
|
||||
reward: demand.reward,
|
||||
date: demand.date,
|
||||
sendcontent: demand.sendcontent
|
||||
})
|
||||
} else if (currentOperation.value === 'delete') {
|
||||
await deleteDemand(pendingDeleteId.value)
|
||||
const updateData = {
|
||||
requester: demand.requester,
|
||||
qq_code: demand.qq_code,
|
||||
content: demand.content,
|
||||
reward: demand.reward,
|
||||
date: demand.date,
|
||||
sendcontent: demand.sendcontent
|
||||
}
|
||||
|
||||
if (currentOperation.value === 'hide') {
|
||||
updateData.status = 'HIDE'
|
||||
} else if (currentOperation.value === 'delete') {
|
||||
updateData.status = 'DEL'
|
||||
}
|
||||
|
||||
console.log('管理员操作 - 更新需求的数据:', updateData)
|
||||
console.log('管理员操作 - 需求ID:', pendingDeleteId.value)
|
||||
|
||||
const result = await updateDemand(pendingDeleteId.value, updateData)
|
||||
console.log('管理员操作 - 更新结果:', result)
|
||||
|
||||
fetchDemands()
|
||||
} catch (e) {
|
||||
console.error('操作失败:', e)
|
||||
console.error('管理员操作失败:', e)
|
||||
console.error('错误详情:', e.response?.data)
|
||||
error.value = `操作失败: ${e.response?.data?.detail || e.message}`
|
||||
} finally {
|
||||
showDeleteConfirm.value = false
|
||||
pendingDeleteId.value = null
|
||||
@ -367,18 +486,35 @@ const confirmRestore = async () => {
|
||||
const demand = demands.value.find(d => d.id === pendingRestoreId.value)
|
||||
if (!demand) return
|
||||
|
||||
const restoredContent = demand.content.replace(/^&DEL/, '')
|
||||
await updateDemand(pendingRestoreId.value, {
|
||||
let updateData = {
|
||||
requester: demand.requester,
|
||||
qq_code: demand.qq_code,
|
||||
content: restoredContent,
|
||||
reward: demand.reward,
|
||||
date: demand.date,
|
||||
sendcontent: demand.sendcontent
|
||||
})
|
||||
sendcontent: demand.sendcontent,
|
||||
status: 'NORMAL'
|
||||
}
|
||||
|
||||
// 判断是新格式还是旧格式
|
||||
if (demand.status) {
|
||||
// 新格式:保持原content
|
||||
updateData.content = demand.content
|
||||
} else {
|
||||
// 旧格式:去掉content的&DEL前缀,并转换为新格式
|
||||
updateData.content = demand.content.replace(/^&DEL/, '')
|
||||
}
|
||||
|
||||
console.log('管理员恢复 - 更新需求的数据:', updateData)
|
||||
console.log('管理员恢复 - 需求ID:', pendingRestoreId.value)
|
||||
|
||||
const result = await updateDemand(pendingRestoreId.value, updateData)
|
||||
console.log('管理员恢复 - 更新结果:', result)
|
||||
|
||||
fetchDemands()
|
||||
} catch (e) {
|
||||
console.error('恢复失败:', e)
|
||||
console.error('错误详情:', e.response?.data)
|
||||
error.value = `恢复失败: ${e.response?.data?.detail || e.message}`
|
||||
} finally {
|
||||
showRestoreConfirm.value = false
|
||||
pendingRestoreId.value = null
|
||||
@ -391,6 +527,7 @@ const cancelRestore = () => {
|
||||
pendingRestoreId.value = null
|
||||
}
|
||||
|
||||
|
||||
// 刷新
|
||||
const onRefresh = () => {
|
||||
fetchDemands()
|
||||
@ -448,42 +585,83 @@ const submitAddForm = async () => {
|
||||
}
|
||||
|
||||
// 解析回复文本
|
||||
function parseReplyText(str) {
|
||||
// 首先尝试解析 qq:内容 格式
|
||||
const qqMatch = str.match(/^(\d+):(.+)$/)
|
||||
if (qqMatch) {
|
||||
async function parseReplyText(str) {
|
||||
// 首先尝试解析新格式:qq:内容 格式
|
||||
const newFormatMatch = str.match(/^(\d+):(.*)$/)
|
||||
if (newFormatMatch) {
|
||||
const qqNumber = newFormatMatch[1]
|
||||
let username = qqNumber // 默认显示QQ号
|
||||
|
||||
// 尝试从缓存获取用户名
|
||||
if (usernameCache.value[qqNumber]) {
|
||||
username = usernameCache.value[qqNumber]
|
||||
} else {
|
||||
// 通过API查询用户名
|
||||
try {
|
||||
const userInfo = await getUserByInfo({ qq_code: qqNumber })
|
||||
if (userInfo && userInfo.username) {
|
||||
username = `${userInfo.username}(${qqNumber})`
|
||||
usernameCache.value[qqNumber] = username
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('获取用户信息失败:', error)
|
||||
// 失败时使用QQ号作为显示名
|
||||
username = qqNumber
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
user: qqMatch[1],
|
||||
content: qqMatch[2].trim()
|
||||
user: username,
|
||||
content: newFormatMatch[2].trim().replace(/\\n/g, ' ').replace(/\\r/g, '').replace(/\\t/g, ' ')
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容原有的昵称(QQ号)格式,允许有空格
|
||||
const match = str.match(/^(.+?[((][1-9][0-9]{4,}[))])(.*)$/)
|
||||
if (match) {
|
||||
// 兼容旧格式:昵称(QQ号):内容 格式
|
||||
const oldFormatMatch = str.match(/^(.+?)\((\d+)\):(.*)$/)
|
||||
if (oldFormatMatch) {
|
||||
const nickname = oldFormatMatch[1].trim()
|
||||
const qqNumber = oldFormatMatch[2]
|
||||
return {
|
||||
user: match[1].trim(),
|
||||
content: match[2].replace(/^:|^:/, '').trim()
|
||||
user: `${nickname}(${qqNumber})`, // 保持旧格式的显示样式
|
||||
content: oldFormatMatch[3].trim().replace(/\\n/g, ' ').replace(/\\r/g, '').replace(/\\t/g, ' ')
|
||||
}
|
||||
}
|
||||
// fallback
|
||||
|
||||
// 更宽松的旧格式匹配:处理可能的变体
|
||||
const flexibleOldMatch = str.match(/^(.+?)[((](\d+)[))][::](.*)$/)
|
||||
if (flexibleOldMatch) {
|
||||
const nickname = flexibleOldMatch[1].trim()
|
||||
const qqNumber = flexibleOldMatch[2]
|
||||
return {
|
||||
user: `${nickname}(${qqNumber})`,
|
||||
content: flexibleOldMatch[3].trim().replace(/\\n/g, ' ').replace(/\\r/g, '').replace(/\\t/g, ' ')
|
||||
}
|
||||
}
|
||||
|
||||
// fallback:如果都不匹配,返回原始内容
|
||||
return {
|
||||
user: '',
|
||||
content: str
|
||||
content: str.replace(/\\n/g, ' ').replace(/\\r/g, '').replace(/\\t/g, ' ')
|
||||
}
|
||||
}
|
||||
|
||||
// 提取QQ号
|
||||
function extractQQ(str) {
|
||||
// 首先尝试解析 qq:内容 格式
|
||||
const qqMatch = str.match(/^(\d+):(.+)$/)
|
||||
if (qqMatch) {
|
||||
return qqMatch[1]
|
||||
// 首先尝试解析新格式:qq:内容 格式
|
||||
const newFormatMatch = str.match(/^(\d+):(.*)$/)
|
||||
if (newFormatMatch) {
|
||||
return newFormatMatch[1]
|
||||
}
|
||||
|
||||
// 兼容原有的昵称(QQ号)格式
|
||||
const match = str.match(/[((]([1-9][0-9]{4,})[))]/)
|
||||
return match ? match[1] : ''
|
||||
// 兼容旧格式:昵称(QQ号):内容 格式
|
||||
const oldFormatMatch = str.match(/^(.+?)\((\d+)\):(.*)$/)
|
||||
if (oldFormatMatch) {
|
||||
return oldFormatMatch[2] // QQ号部分
|
||||
}
|
||||
|
||||
// 更宽松的旧格式匹配
|
||||
const flexibleOldMatch = str.match(/[((](\d+)[))]/);
|
||||
return flexibleOldMatch ? flexibleOldMatch[1] : ''
|
||||
}
|
||||
|
||||
// 组件挂载时自动加载数据
|
||||
@ -652,18 +830,24 @@ onMounted(() => {
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.active {
|
||||
.status-normal {
|
||||
background: #f0f9ff;
|
||||
color: #0369a1;
|
||||
border: 1px solid #7dd3fc;
|
||||
}
|
||||
|
||||
.deleted {
|
||||
.status-deleted {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
border: 1px solid #fca5a5;
|
||||
}
|
||||
|
||||
.status-hidden {
|
||||
background: #fefce8;
|
||||
color: #a16207;
|
||||
border: 1px solid #fcd34d;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
|
@ -163,10 +163,10 @@ const validateForm = () => {
|
||||
// usernameError.value = 'QQ号码只能包含数字'
|
||||
// return false
|
||||
// }
|
||||
if (username.value.length < 4) {
|
||||
usernameError.value = 'QQ号码长度不能小于4个字符'
|
||||
return false
|
||||
}
|
||||
// if (username.value.length < 4) {
|
||||
// usernameError.value = 'QQ号码长度不能小于4个字符'
|
||||
// return false
|
||||
// }
|
||||
|
||||
// 验证密码
|
||||
if (!password.value) {
|
||||
|
@ -118,7 +118,7 @@
|
||||
<h2>需求详情</h2>
|
||||
<div style="display:flex;align-items:center;gap:16px;">
|
||||
<template v-if="isOwner">
|
||||
<!-- <button class="edit-btn big-action-btn" @click="openEditModal">修改</button>-->
|
||||
<button class="edit-btn big-action-btn" @click="openEditModal">修改</button>
|
||||
<button class="delete-btn big-action-btn" @click="handleDeleteDemand">删除</button>
|
||||
</template>
|
||||
<button class="close-btn" @click="closeModal">×</button>
|
||||
|
Loading…
x
Reference in New Issue
Block a user