需求改了好多,不需要自己输用户名和qq号了

This commit is contained in:
Kunagisa 2025-07-10 16:34:35 +08:00
parent d2f8d3fad2
commit c40638eca2
2 changed files with 271 additions and 95 deletions

View File

@ -2,6 +2,7 @@ import axios from 'axios';
import { logoutUser } from '../utils/jwt'; // logoutUser会处理清除存储和重定向
const API_BASE_URL = 'https://api.zybdatasupport.online';
//const API_BASE_URL = 'http://hk.zybdatasupport.online:8000/';
const axiosInstance = axios.create({
baseURL: API_BASE_URL,

View File

@ -20,6 +20,7 @@
<th>需求创建时间</th>
<th>回复数量</th>
<th>回复</th>
<th>状态</th>
</tr>
</thead>
<tbody>
@ -47,6 +48,11 @@
<td>
<button class="btn-common btn-gradient btn-reply" @click.stop="showReply(demand)">回复</button>
</td>
<td class="status">
<span :class="['tag', getStatusClass(demand.status)]">
{{ getStatusText(demand.status) }}
</span>
</td>
</tr>
</tbody>
</table>
@ -61,28 +67,28 @@
</div>
<div class="modal-body">
<form class="add-modal-form" @submit.prevent="submitReply">
<div class="form-row">
<span class="label">昵称</span>
<input
v-model="addForm.author"
class="input"
placeholder="请输入您的昵称"
required
/>
</div>
<div class="form-row">
<span class="label">QQ号</span>
<input
v-model="addForm.author_contact"
class="input"
placeholder="请输入您的QQ号"
type="text"
pattern="[0-9]*"
inputmode="numeric"
readonly
required
/>
</div>
<!-- <div class="form-row">-->
<!-- <span class="label">昵称</span>-->
<!-- <input-->
<!-- v-model="addForm.author"-->
<!-- class="input"-->
<!-- placeholder="请输入您的昵称"-->
<!-- required-->
<!-- />-->
<!-- </div>-->
<!-- <div class="form-row">-->
<!-- <span class="label">QQ号</span>-->
<!-- <input-->
<!-- v-model="addForm.author_contact"-->
<!-- class="input"-->
<!-- placeholder="请输入您的QQ号"-->
<!-- type="text"-->
<!-- pattern="[0-9]*"-->
<!-- inputmode="numeric"-->
<!-- readonly-->
<!-- required-->
<!-- />-->
<!-- </div>-->
<div class="form-row">
<span class="label">内容</span>
<textarea
@ -143,6 +149,12 @@
<span class="label">发布时间</span>
<span class="value">{{ formatDate(selectedDemand?.date) }}</span>
</div>
<div class="detail-item">
<span class="label">状态</span>
<span :class="['tag', getStatusClass(selectedDemand?.status)]">
{{ getStatusText(selectedDemand?.status) }}
</span>
</div>
<div class="reply-section">
<h3>回复内容</h3>
<div class="reply-list">
@ -156,16 +168,20 @@
</div>
</div>
<div v-else class="no-reply">
<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>
暂无回复
</div>
@ -188,22 +204,22 @@
</div>
<div class="modal-body">
<form class="add-modal-form" @submit.prevent="submitAddForm">
<div class="form-row">
<span class="label">请求者</span>
<input v-model="addForm.requester" class="input" placeholder="可选" />
</div>
<div class="form-row">
<span class="label">QQ号</span>
<input
v-model="addForm.qq_code"
class="input"
placeholder="可选"
type="text"
pattern="[0-9]*"
inputmode="numeric"
readonly
/>
</div>
<!-- <div class="form-row">-->
<!-- <span class="label">请求者</span>-->
<!-- <input v-model="addForm.requester" class="input" placeholder="可选" />-->
<!-- </div>-->
<!-- <div class="form-row">-->
<!-- <span class="label">QQ号</span>-->
<!-- <input -->
<!-- v-model="addForm.qq_code" -->
<!-- class="input" -->
<!-- placeholder="可选" -->
<!-- type="text"-->
<!-- pattern="[0-9]*"-->
<!-- inputmode="numeric"-->
<!-- readonly-->
<!-- />-->
<!-- </div>-->
<div class="form-row">
<span class="label">需求内容</span>
<textarea
@ -237,14 +253,14 @@
</div>
<div class="modal-body">
<form class="add-modal-form" @submit.prevent="handleEditSubmit">
<div class="form-row">
<span class="label">请求者</span>
<input v-model="editForm.requester" class="input" required />
</div>
<div class="form-row">
<span class="label">QQ号</span>
<input v-model="editForm.qq_code" class="input" required readonly />
</div>
<!-- <div class="form-row">-->
<!-- <span class="label">请求者</span>-->
<!-- <input v-model="editForm.requester" class="input" required />-->
<!-- </div>-->
<!-- <div class="form-row">-->
<!-- <span class="label">QQ号</span>-->
<!-- <input v-model="editForm.qq_code" class="input" required readonly />-->
<!-- </div>-->
<div class="form-row">
<span class="label">需求内容</span>
<textarea v-model="editForm.content" class="input" rows="3" required></textarea>
@ -262,9 +278,9 @@
<div v-if="showDeleteConfirm" class="modal-overlay" style="z-index:2000;">
<div class="modal-content" style="max-width:350px;text-align:center;">
<div class="modal-header">
<h2 style="color:#F56C6C;">隐藏并删除</h2>
<h2 style="color:#F56C6C;">删除</h2>
</div>
<div class="modal-body" style="font-size:16px;">确定要隐藏并删除该需求吗此操作不可恢复</div>
<div class="modal-body" style="font-size:16px;">确定要删除该需求吗此操作不可恢复</div>
<div class="delete-dialog-footer" style="display:flex;justify-content:center;gap:18px;margin:18px 0 8px 0;">
<button class="confirm-button" @click="confirmDelete">确认</button>
<button class="cancel-button" @click="cancelDelete">取消</button>
@ -279,6 +295,7 @@
import { ref, onMounted, nextTick, computed } from 'vue'
import { getDemandsList, addDemand, updateDemand, deleteDemand, addDemandReply } from '../../api/demands'
import { getStoredUser } from '@/utils/jwt'
import { getUserByInfo } from '../../api/login'
import ErrorDialog from '@/components/ErrorDialog.vue'
//
@ -289,6 +306,7 @@ const showModal = ref(false)
const reply = ref(null)
const replyModal = ref(false)
const selectedDemand = ref(null)
const replyParsedTexts = ref([])
const showAddModal = ref(false)
const addError = ref('')
const addForm = ref({
@ -322,9 +340,23 @@ const isNoReward = (reward) => {
return !reward || reward === '无赏金'
}
// &DEL
//
const filteredDemands = computed(() => {
return demands.value.filter(demand => !demand.content?.startsWith('&DEL'))
const user = getStoredUser()
return demands.value.filter(demand => {
// DEL&DEL
if (demand.status === 'DEL' || demand.content?.startsWith('&DEL')) {
return false
}
//
if (demand.status === 'HIDE') {
return user && demand.qq_code && String(user.qq_code) === String(demand.qq_code)
}
//
return true
})
})
const getReplyCount = (demand) => {
@ -339,6 +371,34 @@ const getReplyCount = (demand) => {
return 0;
}
//
const getStatusClass = (status) => {
switch (status) {
case 'NORMAL':
return 'status-normal'
case 'DEL':
return 'status-deleted'
case 'HIDE':
return 'status-hidden'
default:
return 'status-normal'
}
}
//
const getStatusText = (status) => {
switch (status) {
case 'NORMAL':
return '正常'
case 'DEL':
return '已删除'
case 'HIDE':
return '管理员已隐藏'
default:
return '正常'
}
}
//
const formatDate = (dateString) => {
if (!dateString || dateString === 'Test_date') return '日期未提供'
@ -377,25 +437,44 @@ const fetchDemands = async () => {
}
//
const showReply = (demand) => {
const showReply = async (demand) => {
reply.value = demand
replyModal.value = true
resetReplyForm();
await resetReplyForm();
}
//
const closeReplyModal = () => {
const closeReplyModal = async () => {
replyModal.value = false;
resetReplyForm();
await resetReplyForm();
}
//
const resetReplyForm = () => {
const resetReplyForm = async () => {
// qq_code
const user = getStoredUser()
let authorName = ''
//
if (user && user.qq_code) {
try {
console.log('回复表单 - 正在获取用户信息QQ号:', user.qq_code)
const userInfo = await getUserByInfo({ qq_code: user.qq_code })
console.log('回复表单 - 获取到的用户信息:', userInfo)
// authorName = userInfo.name || ''
authorName = userInfo.username || '' // 使usernamename
console.log('回复表单 - 设置的作者昵称:', authorName)
} catch (error) {
console.log('回复表单 - 获取用户昵称失败:', error)
// 使
authorName = ''
}
}
addForm.value = {
sendcontent: '',
author: '',
// author: '',
author: authorName, // 使
author_contact: user && user.qq_code ? user.qq_code : ''
};
addError.value = '';
@ -406,9 +485,19 @@ const resetReplyForm = () => {
}
//
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
}
}
}
//
@ -418,11 +507,30 @@ const closeModal = () => {
}
//
const openAddModal = () => {
const openAddModal = async () => {
//
const user = getStoredUser()
let requesterName = ''
//
if (user && user.qq_code) {
try {
console.log('正在获取用户信息QQ号:', user.qq_code)
const userInfo = await getUserByInfo({ qq_code: user.qq_code })
console.log('获取到的用户信息:', userInfo)
// requesterName = userInfo.name || ''
requesterName = userInfo.username || '' // 使usernamename
console.log('设置的请求者昵称:', requesterName)
} catch (error) {
console.log('获取用户昵称失败:', error)
// 使
requesterName = ''
}
}
addForm.value = {
requester: '',
// requester: '',
requester: requesterName, // 使
content: '',
reward: '',
qq_code: user && user.qq_code ? user.qq_code : '',
@ -440,11 +548,11 @@ function closeAddModal() {
addError.value = ''
}
// script setup
const validateQQ = (event) => {
//
addForm.value.qq_code = event.target.value.replace(/[^\d]/g, '');
}
// // script setup
// const validateQQ = (event) => {
// //
// addForm.value.qq_code = event.target.value.replace(/[^\d]/g, '');
// }
// submitAddForm QQ
async function submitAddForm() {
@ -504,13 +612,13 @@ const submitReply = async () => {
addError.value = '';
try {
const replyData = {
reply: addForm.value.sendcontent
reply: addForm.value.sendcontent.replace(/\n/g, ' ').replace(/\r/g, ' ')
};
console.log('提交的回复数据:', replyData);
await addDemandReply(reply.value.id, replyData);
replyModal.value = false;
resetReplyForm();
await resetReplyForm();
fetchDemands(); //
} catch (e) {
console.error('提交回复失败:', e);
@ -536,40 +644,83 @@ function autoResize() {
}
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] : ''
}
function parseReplyText(str) {
// qq:
const qqMatch = str.match(/^(\d+):(.+)$/)
if (qqMatch) {
//
const usernameCache = ref({})
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, '\n').replace(/\\r/g, '').replace(/\\t/g, ' ')
}
}
// QQ
const match = str.match(/^(.+?[(][1-9][0-9]{4,}[)])(.*)$/)
if (match) {
// match[1] QQmatch[2] " xxx "
// 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, ' ')
}
}
@ -623,15 +774,15 @@ function handleDeleteDemand() {
async function confirmDelete() {
try {
// 使updateDemand APIcontent&DEL
const updatedContent = `&DEL${selectedDemand.value.content}`
// DELcontent
await updateDemand(pendingDeleteId.value, {
requester: selectedDemand.value.requester,
qq_code: selectedDemand.value.qq_code,
content: updatedContent,
content: selectedDemand.value.content,
reward: selectedDemand.value.reward,
date: selectedDemand.value.date,
sendcontent: selectedDemand.value.sendcontent
sendcontent: selectedDemand.value.sendcontent,
status: 'DEL'
})
fetchDemands()
closeModal()
@ -742,8 +893,27 @@ const onRefresh = () => {
border: 1px solid #b6d2ff;
}
.status-normal {
background: #f0f9ff;
color: #0369a1;
border: 1px solid #7dd3fc;
}
.status-deleted {
background: #fef2f2;
color: #dc2626;
border: 1px solid #fca5a5;
}
.status-hidden {
background: #fefce8;
color: #a16207;
border: 1px solid #fcd34d;
}
.maps-table td.reward,
.maps-table td.reply-count,
.maps-table td.status,
.maps-table tr {
box-shadow: none !important;
filter: none !important;
@ -1039,6 +1209,11 @@ const onRefresh = () => {
font-size: 15px;
}
.reply-content-with-newlines {
white-space: pre-wrap; /* 保留换行符和空白字符 */
word-wrap: break-word; /* 长单词自动换行 */
}
.warning-tip {
background: linear-gradient(90deg, #ffeaea 0%, #ffd6d6 100%);
color: #d32f2f;