细节优化——1

This commit is contained in:
Cheng Zhou
2025-12-30 14:07:57 +08:00
parent 71db309e12
commit 0c1fc49f17
40 changed files with 1610 additions and 389 deletions
+116
View File
@@ -0,0 +1,116 @@
<template>
<div class="thread-composer">
<div v-if="quoteItem" class="quote-box">
<div class="quote-meta">
引用 {{ displayUser(quoteItem.created_by, { users: userMap, members: memberMap }) }}
· {{ displayDateTime(quoteItem.created_at) }}
<el-button type="text" size="small" @click="$emit('clear-quote')">取消引用</el-button>
</div>
<div class="quote-content">{{ quoteContent(quoteItem) }}</div>
</div>
<el-input v-model="contentProxy" type="textarea" rows="3" placeholder="输入内容" />
<div v-if="allowAttachments" class="upload-row">
<div class="upload-label">附件</div>
<el-upload v-model:file-list="fileListProxy" :auto-upload="false" multiple list-type="picture" class="thread-upload">
<el-button size="small" class="upload-button">上传附件</el-button>
</el-upload>
</div>
<div class="actions">
<el-button v-if="showCancel" size="small" @click="$emit('cancel')">取消</el-button>
<el-button size="small" type="primary" :loading="submitting" @click="$emit('submit')">提交</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import type { UploadUserFile } from "element-plus";
import { displayDateTime, displayUser } from "../utils/display";
const props = defineProps<{
modelValue: string;
fileList: UploadUserFile[];
submitting?: boolean;
showCancel?: boolean;
allowAttachments?: boolean;
quoteItem?: any | null;
memberMap?: Record<string, string>;
userMap?: Record<string, string>;
}>();
const emit = defineEmits<{
(e: "update:modelValue", value: string): void;
(e: "update:fileList", value: UploadUserFile[]): void;
(e: "submit"): void;
(e: "cancel"): void;
(e: "clear-quote"): void;
}>();
const contentProxy = computed({
get: () => props.modelValue,
set: (val: string) => emit("update:modelValue", val),
});
const fileListProxy = computed({
get: () => props.fileList,
set: (val: UploadUserFile[]) => emit("update:fileList", val),
});
const quoteContent = (item: any) => (item?.is_deleted ? "内容已删除" : item?.content || "—");
</script>
<style scoped>
.thread-composer {
margin-bottom: 8px;
}
.upload-row {
display: flex;
align-items: center;
gap: 10px;
margin-top: 10px;
}
.upload-label {
font-size: 12px;
color: #606266;
padding: 4px 8px;
border-radius: 999px;
background: #f2f4f7;
}
.thread-upload :deep(.el-upload-list) {
margin-top: 6px;
}
.upload-button {
border: 1px dashed #3b82f6;
color: #1d4ed8;
background: #eff6ff;
font-weight: 600;
}
.upload-button:hover {
border-color: #2563eb;
color: #1e40af;
background: #e0ecff;
}
.actions {
margin-top: 8px;
display: flex;
justify-content: flex-end;
gap: 8px;
}
.quote-box {
background: #f5f7fa;
border-left: 3px solid #dcdfe6;
padding: 8px 10px;
border-radius: 4px;
margin-bottom: 8px;
}
.quote-meta {
display: flex;
justify-content: space-between;
color: #909399;
font-size: 12px;
margin-bottom: 6px;
}
.quote-content {
white-space: pre-wrap;
}
</style>