| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- <template>
- <div class="success-case-list-container">
- <h2 class="page-title">成功案例管理</h2>
-
- <el-card shadow="never" class="toolbar-card">
- <el-row :gutter="20">
- <el-col :span="18">
- <el-space wrap>
- <el-button type="primary" icon="Plus" @click="$router.push('/success-case/create')">新增案例</el-button>
- <el-button icon="Refresh" @click="loadList">刷新</el-button>
- </el-space>
- </el-col>
- <el-col :span="6">
- <!-- 预留搜索区域 -->
- </el-col>
- </el-row>
- </el-card>
-
- <el-card shadow="never" class="table-card">
- <el-table v-loading="loading" :data="list" stripe>
- <el-table-column type="index" label="序号" width="60" :index="indexMethod" />
- <el-table-column label="案例编号" width="140">
- <template #default="{ row }">
- {{ row.caseNo || row.case_no || '-' }}
- </template>
- </el-table-column>
- <el-table-column prop="maleUserNickname" label="男方昵称" width="120" />
- <el-table-column prop="femaleUserNickname" label="女方昵称" width="120" />
- <el-table-column prop="quote" label="案例引言" min-width="200" show-overflow-tooltip />
- <el-table-column prop="marriageDate" label="结婚日期" width="120" />
- <el-table-column prop="matchmakerName" label="红娘" width="100" />
- <el-table-column prop="caseStatus" label="状态" width="100">
- <template #default="{ row }">
- <el-switch v-model="row.caseStatus" :active-value="1" :inactive-value="0" @change="handleStatusChange(row)" />
- </template>
- </el-table-column>
- <el-table-column prop="createdAt" label="创建时间" width="180" />
- <el-table-column label="操作" width="200" fixed="right">
- <template #default="{ row }">
- <el-button type="info" size="small" link @click="handleViewDetail(row)">查看</el-button>
- <el-button type="primary" size="small" link @click="$router.push(`/success-case/edit/${row.caseId || row.case_id}`)">编辑</el-button>
- <el-button type="danger" size="small" link @click="handleDelete(row)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
-
- <div class="pagination-container">
- <el-pagination
- v-model:current-page="currentPage"
- v-model:page-size="pageSize"
- :total="total"
- :page-sizes="[10, 20, 50, 100]"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="loadList"
- @current-change="loadList"
- />
- </div>
- </el-card>
-
- <!-- 案例详情对话框 -->
- <el-dialog v-model="detailVisible" title="案例详情" width="900px" :close-on-click-modal="false">
- <div v-loading="detailLoading" class="detail-container">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="案例编号" :span="2">
- <el-tag type="primary">{{ detailData.caseNo }}</el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="男方昵称">{{ detailData.maleUserNickname }}</el-descriptions-item>
- <el-descriptions-item label="女方昵称">{{ detailData.femaleUserNickname }}</el-descriptions-item>
- <el-descriptions-item label="结婚日期">{{ detailData.marriageDate }}</el-descriptions-item>
- <el-descriptions-item label="红娘">{{ detailData.matchmakerName }}</el-descriptions-item>
- <el-descriptions-item label="状态" :span="2">
- <el-tag :type="detailData.caseStatus === 1 ? 'success' : 'info'">
- {{ detailData.caseStatus === 1 ? '展示中' : '隐藏' }}
- </el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="案例引言" :span="2">
- {{ detailData.quote || '暂无' }}
- </el-descriptions-item>
- <el-descriptions-item label="案例故事" :span="2">
- <div class="story-content">{{ detailData.story || '暂无' }}</div>
- </el-descriptions-item>
- <el-descriptions-item label="创建时间" :span="2">
- {{ detailData.createdAt }}
- </el-descriptions-item>
- </el-descriptions>
-
- <!-- 时间线 -->
- <div v-if="detailData.timeline && detailData.timeline.length > 0" class="timeline-section">
- <h3 class="section-title">案例时间线</h3>
- <el-timeline>
- <el-timeline-item
- v-for="item in detailData.timeline"
- :key="item.timelineId"
- :timestamp="item.timelineDate"
- placement="top"
- >
- <el-card>
- <h4>{{ item.timelineTitle }}</h4>
- <p>{{ item.timelineDesc }}</p>
- </el-card>
- </el-timeline-item>
- </el-timeline>
- </div>
- </div>
-
- <template #footer>
- <el-button @click="detailVisible = false">关闭</el-button>
- <el-button type="primary" @click="handleEditFromDetail">编辑此案例</el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup>
- import { ref, onMounted, computed } from 'vue'
- import { useRouter } from 'vue-router'
- import { ElMessage, ElMessageBox } from 'element-plus'
- import request from '@/utils/request'
- import { API_ENDPOINTS } from '@/config/api'
- const router = useRouter()
- const loading = ref(false)
- const currentPage = ref(1)
- const pageSize = ref(10)
- const total = ref(0)
- const list = ref([])
- // 详情对话框
- const detailVisible = ref(false)
- const detailLoading = ref(false)
- const detailData = ref({})
- // 序号计算方法
- const indexMethod = (index) => {
- return (currentPage.value - 1) * pageSize.value + index + 1
- }
- const loadList = async () => {
- loading.value = true
- try {
- const response = await request.get(API_ENDPOINTS.CASE_LIST, {
- params: {
- page: currentPage.value,
- pageSize: pageSize.value
- }
- })
-
- console.log('案例列表响应:', response)
-
- if (response.code === 200) {
- let dataList = response.data.list || response.data || []
-
- // 兼容处理:如果后端返回的是下划线格式,转换为驼峰格式
- list.value = dataList.map(item => ({
- ...item,
- caseId: item.caseId || item.case_id,
- caseNo: item.caseNo || item.case_no,
- caseStatus: item.caseStatus !== undefined ? item.caseStatus : item.case_status,
- maleUserNickname: item.maleUserNickname || item.male_user_nickname,
- femaleUserNickname: item.femaleUserNickname || item.female_user_nickname,
- marriageDate: item.marriageDate || item.marriage_date,
- matchmakerName: item.matchmakerName || item.matchmaker_name,
- quote: item.quote,
- createdAt: item.createdAt || item.created_at
- }))
-
- total.value = response.data.total || list.value.length
-
- console.log('案例列表数据:', list.value)
- console.log('总数:', total.value)
- } else {
- ElMessage.error(response.message || '加载失败')
- }
- } catch (error) {
- console.error('加载失败:', error)
- ElMessage.error('加载失败:' + (error.message || '网络错误'))
- } finally {
- loading.value = false
- }
- }
- const handleStatusChange = async (row) => {
- // 兼容处理:支持 caseId 和 case_id 两种格式
- const caseId = row.caseId || row.case_id
- if (!row || !caseId) {
- ElMessage.error('案例ID不存在,无法更新状态')
- return
- }
-
- try {
- // 获取当前状态值(兼容驼峰和下划线格式)
- const currentStatus = row.caseStatus !== undefined ? row.caseStatus : row.case_status
-
- // 由于实体类添加了 @JsonProperty 注解,发送驼峰格式
- const response = await request.put(`${API_ENDPOINTS.CASE_UPDATE}/${caseId}`, {
- caseStatus: currentStatus
- })
-
- if (response.code === 200) {
- ElMessage.success('状态更新成功')
- } else {
- // 回滚状态
- row.caseStatus = currentStatus === 1 ? 0 : 1
- ElMessage.error(response.message || '状态更新失败')
- }
- } catch (error) {
- console.error('状态更新失败:', error)
- // 回滚状态
- const currentStatus = row.caseStatus !== undefined ? row.caseStatus : row.case_status
- row.caseStatus = currentStatus === 1 ? 0 : 1
- ElMessage.error('状态更新失败')
- }
- }
- const handleViewDetail = async (row) => {
- detailVisible.value = true
- detailLoading.value = true
- detailData.value = {}
-
- try {
- // 兼容处理:支持 caseId 和 case_id 两种格式
- const caseId = row.caseId || row.case_id
- if (!caseId) {
- ElMessage.error('案例ID不存在')
- detailVisible.value = false
- return
- }
-
- const response = await request.get(`${API_ENDPOINTS.CASE_DETAIL}/${caseId}`)
-
- console.log('案例详情响应:', response)
-
- if (response.code === 200) {
- const data = response.data || {}
- // 兼容处理:如果后端返回的是下划线格式,转换为驼峰格式
- detailData.value = {
- ...data,
- caseId: data.caseId || data.case_id,
- caseNo: data.caseNo || data.case_no,
- caseStatus: data.caseStatus !== undefined ? data.caseStatus : data.case_status,
- maleUserNickname: data.maleUserNickname || data.male_user_nickname,
- femaleUserNickname: data.femaleUserNickname || data.female_user_nickname,
- marriageDate: data.marriageDate || data.marriage_date,
- matchmakerName: data.matchmakerName || data.matchmaker_name,
- quote: data.quote,
- story: data.story,
- createdAt: data.createdAt || data.created_at
- }
- console.log('案例详情数据:', detailData.value)
- } else {
- ElMessage.error(response.message || '加载详情失败')
- detailVisible.value = false
- }
- } catch (error) {
- console.error('加载详情失败:', error)
- ElMessage.error('加载详情失败:' + (error.message || '网络错误'))
- detailVisible.value = false
- } finally {
- detailLoading.value = false
- }
- }
- const handleEditFromDetail = () => {
- if (detailData.value.caseId) {
- detailVisible.value = false
- router.push(`/success-case/edit/${detailData.value.caseId}`)
- }
- }
- const handleDelete = async (row) => {
- try {
- // 兼容处理:支持 caseNo 和 case_no 两种格式
- const caseNo = row.caseNo || row.case_no || '该案例'
- await ElMessageBox.confirm(
- `确定要删除案例"${caseNo}"吗?删除后将无法恢复!`,
- '删除确认',
- {
- type: 'warning',
- confirmButtonText: '确定删除',
- cancelButtonText: '取消'
- }
- )
-
- // 兼容处理:支持 caseId 和 case_id 两种格式
- const caseId = row.caseId || row.case_id
- if (!caseId) {
- ElMessage.error('案例ID不存在')
- return
- }
-
- const response = await request.delete(`${API_ENDPOINTS.CASE_DELETE}/${caseId}`)
-
- if (response.code === 200) {
- ElMessage.success('删除成功')
- // 如果当前页只有一条数据且不是第一页,则返回上一页
- if (list.value.length === 1 && currentPage.value > 1) {
- currentPage.value--
- }
- loadList()
- } else {
- ElMessage.error(response.message || '删除失败')
- }
- } catch (error) {
- if (error !== 'cancel') {
- console.error('删除失败:', error)
- ElMessage.error('删除失败')
- }
- }
- }
- onMounted(() => {
- loadList()
- })
- </script>
- <style scoped>
- .success-case-list-container {
- padding: 20px;
- }
- .page-title {
- margin: 0 0 20px 0;
- font-size: 24px;
- font-weight: 600;
- color: #303133;
- }
- .toolbar-card {
- margin-bottom: 20px;
- }
- .table-card {
- margin-bottom: 20px;
- }
- .pagination-container { display: flex; justify-content: flex-end; margin-top: 20px; }
- /* 详情对话框样式 */
- .detail-container {
- max-height: 70vh;
- overflow-y: auto;
- }
- .story-content {
- line-height: 1.8;
- white-space: pre-wrap;
- word-break: break-all;
- }
- .section-title {
- font-size: 16px;
- font-weight: bold;
- color: #333;
- margin: 20px 0 15px;
- padding-bottom: 10px;
- border-bottom: 2px solid #409eff;
- }
- /* 时间线样式 */
- .timeline-section {
- margin-top: 20px;
- }
- .timeline-section h4 {
- margin: 0 0 8px;
- font-size: 14px;
- color: #333;
- }
- .timeline-section p {
- margin: 0;
- font-size: 13px;
- color: #666;
- line-height: 1.6;
- }
- </style>
|