caojp 1 mesiac pred
rodič
commit
114a8c66a4

+ 223 - 0
marriageAdmin-vue/src/views/dynamic/DynamicDetail.vue

@@ -0,0 +1,223 @@
+<template>
+  <div class="dynamic-detail-container">
+    <h2 class="page-title">动态详情</h2>
+
+    <el-card shadow="never">
+      <div v-loading="loading" class="detail-body">
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="动态ID">
+            <span class="detail-value">{{ detail.dynamicId || '-' }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="用户ID">
+            <span class="detail-value">{{ detail.userId || '-' }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="用户昵称">
+            <span class="detail-value">{{ detail.userNickname || '-' }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="审核状态">
+            <el-tag :type="getAuditStatusType(detail.auditStatus)">
+              {{ getAuditStatusText(detail.auditStatus) }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="点赞数">
+            <span class="detail-value">{{ detail.likeCount ?? 0 }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="评论数">
+            <span class="detail-value">{{ detail.commentCount ?? 0 }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="发布时间">
+            <span class="detail-value">{{ detail.createTime || detail.createdAt || '-' }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="更新时间">
+            <span class="detail-value">{{ detail.updateTime || detail.updatedAt || '-' }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="内容" :span="2">
+            <div class="text-content">{{ detail.content || '暂无内容' }}</div>
+          </el-descriptions-item>
+          <el-descriptions-item label="媒体" :span="2">
+            <div v-if="mediaList.length" class="media-grid">
+              <el-image
+                v-for="(url, index) in mediaList"
+                :key="index"
+                :src="url"
+                fit="cover"
+                :preview-src-list="mediaList"
+                preview-teleported
+                hide-on-click-modal
+                class="media-item"
+              >
+                <template #error>
+                  <div class="image-error">
+                    <el-icon><Picture /></el-icon>
+                    <span>加载失败</span>
+                  </div>
+                </template>
+              </el-image>
+            </div>
+            <span v-else class="text-muted">暂无媒体</span>
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+
+      <div class="detail-actions">
+        <el-button @click="goBack">返回列表</el-button>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { computed, onMounted, ref } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { ElMessage } from 'element-plus'
+import { Picture } from '@element-plus/icons-vue'
+import request from '@/utils/request'
+import { API_ENDPOINTS } from '@/config/api'
+
+const route = useRoute()
+const router = useRouter()
+
+const loading = ref(false)
+const detail = ref({})
+
+// 开发环境通过 Vite 代理转发静态资源
+const BASE = import.meta.env.DEV ? 'http://localhost:8083' : ''
+
+const mediaList = computed(() => formatMediaUrls(detail.value.mediaUrls))
+
+const getAuditStatusText = (status) => {
+  const texts = { 0: '待审核', 1: '已通过', 2: '未通过' }
+  return texts[status] || '未知'
+}
+
+const getAuditStatusType = (status) => {
+  const types = { 0: 'warning', 1: 'success', 2: 'danger' }
+  return types[status] || 'info'
+}
+
+const formatMediaUrls = (raw) => {
+  if (!raw) return []
+  let urls = []
+  const trimmed = String(raw).trim()
+  try {
+    if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
+      const arr = JSON.parse(trimmed)
+      if (Array.isArray(arr)) {
+        urls = arr
+      }
+    }
+  } catch (e) {
+    // ignore JSON parse error
+  }
+  if (!urls.length) {
+    urls = trimmed.split(',').map((item) => item.trim()).filter(Boolean)
+  }
+
+  return urls
+    .map((u) => {
+      let url = u
+      if ((url.startsWith('"') && url.endsWith('"')) || (url.startsWith("'") && url.endsWith("'"))) {
+        url = url.substring(1, url.length - 1)
+      }
+      return url.startsWith('http') ? url : `${BASE}${url}`
+    })
+    .filter(Boolean)
+}
+
+const loadDetail = async () => {
+  if (!route.params.id) {
+    ElMessage.error('缺少动态ID')
+    router.back()
+    return
+  }
+
+  loading.value = true
+  try {
+    const res = await request.get(`${API_ENDPOINTS.DYNAMIC_DETAIL}/${route.params.id}`)
+    if (res.code === 200) {
+      detail.value = res.data || {}
+    } else {
+      ElMessage.error(res.message || '加载失败')
+    }
+  } catch (error) {
+    console.error('加载动态详情失败', error)
+    ElMessage.error('加载失败:' + (error.message || '网络错误'))
+  } finally {
+    loading.value = false
+  }
+}
+
+const goBack = () => {
+  router.push('/dynamic')
+}
+
+onMounted(loadDetail)
+</script>
+
+<style scoped>
+.dynamic-detail-container {
+  padding: 0;
+}
+
+.page-title {
+  font-size: 24px;
+  font-weight: bold;
+  color: #333;
+  margin: 0 0 20px 0;
+}
+
+.detail-body {
+  min-height: 200px;
+}
+
+.detail-value {
+  color: #333;
+  font-weight: 500;
+}
+
+.text-content {
+  color: #555;
+  line-height: 1.8;
+  white-space: pre-wrap;
+  word-break: break-word;
+}
+
+.text-muted {
+  color: #999;
+}
+
+.media-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+  gap: 12px;
+  margin-top: 6px;
+}
+
+.media-item {
+  width: 100%;
+  height: 120px;
+  border-radius: 6px;
+  border: 1px solid #ebeef5;
+  overflow: hidden;
+}
+
+.image-error {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  color: #909399;
+  font-size: 13px;
+}
+
+.detail-actions {
+  margin-top: 24px;
+  padding-top: 16px;
+  border-top: 1px solid #ebeef5;
+  text-align: right;
+}
+</style>
+
+

+ 248 - 0
marriageAdmin-vue/src/views/matchmaker/MatchmakerAudit.vue

@@ -0,0 +1,248 @@
+<template>
+  <div class="matchmaker-audit-container">
+    <h2 class="page-title">红娘审核</h2>
+
+    <el-card shadow="never" class="toolbar-card">
+      <el-space wrap>
+        <el-input
+          v-model="filters.name"
+          placeholder="按姓名模糊搜索"
+          clearable
+          style="width: 200px"
+          @keyup.enter="loadList"
+        >
+          <template #append>
+            <el-button icon="Search" @click="loadList" />
+          </template>
+        </el-input>
+        <el-input
+          v-model="filters.phone"
+          placeholder="按手机号模糊搜索"
+          clearable
+          style="width: 200px"
+          @keyup.enter="loadList"
+        >
+          <template #append>
+            <el-button icon="Search" @click="loadList" />
+          </template>
+        </el-input>
+        <el-button icon="Refresh" @click="resetFilters">重置</el-button>
+      </el-space>
+    </el-card>
+
+    <el-card shadow="never" class="table-card">
+      <el-table v-loading="loading" :data="list" stripe>
+        <template #empty>
+          <div class="custom-empty-state">
+            <el-icon class="empty-icon"><User /></el-icon>
+            <div class="empty-text">暂无红娘申请</div>
+            <div class="empty-hint">等待用户提交申请后在此审核</div>
+          </div>
+        </template>
+
+        <el-table-column type="index" label="序号" width="60" />
+        <el-table-column prop="name" label="姓名" min-width="100">
+          <template #default="{ row }">
+            <span class="data-highlight">{{ row.name || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="phone" label="手机号" min-width="140" />
+        <el-table-column prop="age" label="年龄" width="80" align="center" />
+        <el-table-column prop="gender" label="性别" width="90" align="center">
+          <template #default="{ row }">
+            <el-tag size="small" effect="light">
+              {{ row.gender === 1 ? '男' : row.gender === 2 ? '女' : '未知' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="area" label="地区" min-width="140" />
+        <el-table-column prop="experience" label="经验" min-width="140" show-overflow-tooltip />
+        <el-table-column prop="introduction" label="简介" min-width="160" show-overflow-tooltip />
+        <el-table-column prop="createTime" label="申请时间" width="180">
+          <template #default="{ row }">
+            <span class="text-muted">{{ row.createTime || row.create_time || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="180" fixed="right">
+          <template #default="{ row }">
+            <el-button
+              type="primary"
+              size="small"
+              @click="handleApprove(row)"
+              :loading="approvingId === row.applyId"
+              :disabled="isApproved(row)"
+            >
+              {{ isApproved(row) ? '审核成功' : '审核通过' }}
+            </el-button>
+            <el-button
+              type="danger"
+              size="small"
+              @click="handleDelete(row)"
+              :loading="deletingId === row.applyId"
+            >
+              删除
+            </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>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { User } from '@element-plus/icons-vue'
+import request from '@/utils/request'
+import { API_ENDPOINTS } from '@/config/api'
+
+const loading = ref(false)
+const list = ref([])
+const total = ref(0)
+const currentPage = ref(1)
+const pageSize = ref(10)
+const approvingId = ref(null)
+const deletingId = ref(null)
+
+const filters = reactive({
+  name: '',
+  phone: ''
+})
+
+const loadList = async () => {
+  loading.value = true
+  try {
+    const params = {
+      page: currentPage.value,
+      pageSize: pageSize.value
+    }
+    if (filters.name && filters.name.trim()) {
+      params.name = filters.name.trim()
+    }
+    if (filters.phone && filters.phone.trim()) {
+      params.phone = filters.phone.trim()
+    }
+    const res = await request.get(API_ENDPOINTS.MATCHMAKER_AUDIT_LIST, { params })
+    if (res.code === 200) {
+      const data = res.data || {}
+      list.value = data.list || data.records || []
+      total.value = data.total || list.value.length
+    }
+  } catch (error) {
+    console.error('加载审核列表失败:', error)
+    ElMessage.error('加载审核列表失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+const resetFilters = () => {
+  filters.name = ''
+  filters.phone = ''
+  currentPage.value = 1
+  loadList()
+}
+
+// 判断是否已审核通过(根据updateMan字段判断)
+const isApproved = (row) => {
+  return !!(row.updateMan || row.update_man)
+}
+
+// 审核通过
+const handleApprove = async (row) => {
+  if (!row.userId) {
+    ElMessage.error('用户ID不存在,无法审核')
+    return
+  }
+  
+  try {
+    await ElMessageBox.confirm(
+      `确定要通过 ${row.name || '该用户'} 的红娘申请吗?通过后该用户将成为红娘。`,
+      '确认审核',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }
+    )
+    
+    approvingId.value = row.applyId
+    const res = await request.post(
+      `${API_ENDPOINTS.MATCHMAKER_AUDIT_APPROVE}/${row.applyId}`,
+      null,
+      { params: { userId: row.userId } }
+    )
+    
+    if (res.code === 200) {
+      ElMessage.success('审核通过成功')
+      loadList()
+    } else {
+      ElMessage.error(res.msg || '审核通过失败')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('审核通过失败:', error)
+      ElMessage.error(error.response?.data?.msg || error.message || '审核通过失败')
+    }
+  } finally {
+    approvingId.value = null
+  }
+}
+
+// 删除申请
+const handleDelete = async (row) => {
+  try {
+    await ElMessageBox.confirm(
+      `确定要删除 ${row.name || '该用户'} 的红娘申请吗?此操作不可恢复。`,
+      '确认删除',
+      {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }
+    )
+    
+    deletingId.value = row.applyId
+    const res = await request.delete(
+      `${API_ENDPOINTS.MATCHMAKER_AUDIT_DELETE}/${row.applyId}`
+    )
+    
+    if (res.code === 200) {
+      ElMessage.success('删除成功')
+      loadList()
+    } else {
+      ElMessage.error(res.msg || '删除失败')
+    }
+  } catch (error) {
+    if (error !== 'cancel') {
+      console.error('删除失败:', error)
+      ElMessage.error(error.response?.data?.msg || error.message || '删除失败')
+    }
+  } finally {
+    deletingId.value = null
+  }
+}
+
+onMounted(loadList)
+</script>
+
+<style scoped>
+@import '@/assets/list-common.css';
+
+.matchmaker-audit-container {
+  padding: 0;
+}
+</style>
+

+ 176 - 0
service/admin/src/main/java/com/zhentao/entity/MarrApply.java

@@ -0,0 +1,176 @@
+package com.zhentao.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 红娘申请表
+ * @TableName marr_apply
+ */
+@TableName(value ="marr_apply")
+@Data
+public class MarrApply {
+    /**
+     * 红娘申请id
+     */
+    @TableId
+    private Long applyId;
+
+    /**
+     * 用户id
+     */
+    private Integer userId;
+
+    /**
+     * 姓名
+     */
+    private String name;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 电子邮箱
+     */
+    private String email;
+
+    /**
+     * 年龄
+     */
+    private Integer age;
+
+    /**
+     * 0-未知,1-男,2-女
+     */
+    private Integer gender;
+
+    /**
+     * 所在地区
+     */
+    private String area;
+
+    /**
+     * 婚姻介绍经验
+     */
+    private String experience;
+
+    /**
+     * 可服务时间
+     */
+    private Date serverTime;
+
+    /**
+     * 个人简介
+     */
+    private String introduction;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 创建人
+     */
+    private String createMan;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    /**
+     * 更新人
+     */
+    private String updateMan;
+
+    /**
+     * 状态0-正常,1-禁止
+     */
+    private Integer status;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        MarrApply other = (MarrApply) that;
+        return (this.getApplyId() == null ? other.getApplyId() == null : this.getApplyId().equals(other.getApplyId()))
+            && (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId()))
+            && (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName()))
+            && (this.getPhone() == null ? other.getPhone() == null : this.getPhone().equals(other.getPhone()))
+            && (this.getEmail() == null ? other.getEmail() == null : this.getEmail().equals(other.getEmail()))
+            && (this.getAge() == null ? other.getAge() == null : this.getAge().equals(other.getAge()))
+            && (this.getGender() == null ? other.getGender() == null : this.getGender().equals(other.getGender()))
+            && (this.getArea() == null ? other.getArea() == null : this.getArea().equals(other.getArea()))
+            && (this.getExperience() == null ? other.getExperience() == null : this.getExperience().equals(other.getExperience()))
+            && (this.getServerTime() == null ? other.getServerTime() == null : this.getServerTime().equals(other.getServerTime()))
+            && (this.getIntroduction() == null ? other.getIntroduction() == null : this.getIntroduction().equals(other.getIntroduction()))
+            && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+            && (this.getCreateMan() == null ? other.getCreateMan() == null : this.getCreateMan().equals(other.getCreateMan()))
+            && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()))
+            && (this.getUpdateMan() == null ? other.getUpdateMan() == null : this.getUpdateMan().equals(other.getUpdateMan()))
+            && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getApplyId() == null) ? 0 : getApplyId().hashCode());
+        result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode());
+        result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
+        result = prime * result + ((getPhone() == null) ? 0 : getPhone().hashCode());
+        result = prime * result + ((getEmail() == null) ? 0 : getEmail().hashCode());
+        result = prime * result + ((getAge() == null) ? 0 : getAge().hashCode());
+        result = prime * result + ((getGender() == null) ? 0 : getGender().hashCode());
+        result = prime * result + ((getArea() == null) ? 0 : getArea().hashCode());
+        result = prime * result + ((getExperience() == null) ? 0 : getExperience().hashCode());
+        result = prime * result + ((getServerTime() == null) ? 0 : getServerTime().hashCode());
+        result = prime * result + ((getIntroduction() == null) ? 0 : getIntroduction().hashCode());
+        result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+        result = prime * result + ((getCreateMan() == null) ? 0 : getCreateMan().hashCode());
+        result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+        result = prime * result + ((getUpdateMan() == null) ? 0 : getUpdateMan().hashCode());
+        result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", applyId=").append(applyId);
+        sb.append(", userId=").append(userId);
+        sb.append(", name=").append(name);
+        sb.append(", phone=").append(phone);
+        sb.append(", email=").append(email);
+        sb.append(", age=").append(age);
+        sb.append(", gender=").append(gender);
+        sb.append(", area=").append(area);
+        sb.append(", experience=").append(experience);
+        sb.append(", serverTime=").append(serverTime);
+        sb.append(", introduction=").append(introduction);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", createMan=").append(createMan);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", updateMan=").append(updateMan);
+        sb.append(", status=").append(status);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 23 - 0
service/admin/src/main/java/com/zhentao/mapper/MarrApplyMapper.java

@@ -0,0 +1,23 @@
+package com.zhentao.mapper;
+
+import com.zhentao.entity.MarrApply;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+
+/**
+* @author 联想
+* @description 针对表【marr_apply(红娘申请表)】的数据库操作Mapper
+* @createDate 2025-12-08 16:36:04
+* @Entity com.zhentao.entity.MarrApply
+*/
+public interface MarrApplyMapper extends BaseMapper<MarrApply> {
+
+    /**
+     * 分页查询红娘申请,支持姓名/手机号模糊查询并按创建时间倒序
+     */
+    Page<MarrApply> selectPageByCondition(Page<MarrApply> page,
+                                          @Param("name") String name,
+                                          @Param("phone") String phone);
+}

+ 30 - 0
service/admin/src/main/java/com/zhentao/service/MarrApplyService.java

@@ -0,0 +1,30 @@
+package com.zhentao.service;
+
+import com.zhentao.entity.MarrApply;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+* @author 联想
+* @description 针对表【marr_apply(红娘申请表)】的数据库操作Service
+* @createDate 2025-12-08 16:36:04
+*/
+public interface MarrApplyService extends IService<MarrApply> {
+
+    /**
+     * 分页查询红娘申请,支持姓名或手机号模糊搜索,按创建时间倒序
+     */
+    Page<MarrApply> pageQuery(Integer pageNum, Integer pageSize, String name, String phone);
+    
+    /**
+     * 审核通过:更新用户isMatchmaker为1
+     */
+    boolean approve(Long applyId, Integer userId);
+    
+    /**
+     * 删除申请
+     */
+    boolean delete(Long applyId);
+}

+ 75 - 0
service/admin/src/main/java/com/zhentao/service/impl/MarrApplyServiceImpl.java

@@ -0,0 +1,75 @@
+package com.zhentao.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zhentao.entity.MarrApply;
+import com.zhentao.entity.Users;
+import com.zhentao.service.MarrApplyService;
+import com.zhentao.mapper.MarrApplyMapper;
+import com.zhentao.mapper.UsersMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+
+/**
+* @author 联想
+* @description 针对表【marr_apply(红娘申请表)】的数据库操作Service实现
+* @createDate 2025-12-08 16:36:04
+*/
+@Service
+public class MarrApplyServiceImpl extends ServiceImpl<MarrApplyMapper, MarrApply>
+    implements MarrApplyService{
+
+    @Autowired
+    private UsersMapper usersMapper;
+
+    @Override
+    public Page<MarrApply> pageQuery(Integer pageNum, Integer pageSize, String name, String phone) {
+        Page<MarrApply> page = new Page<>(pageNum == null ? 1 : pageNum, pageSize == null ? 10 : pageSize);
+        String nameKeyword = StringUtils.hasText(name) ? name.trim() : null;
+        String phoneKeyword = StringUtils.hasText(phone) ? phone.trim() : null;
+        this.baseMapper.selectPageByCondition(page, nameKeyword, phoneKeyword);
+        return page;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean approve(Long applyId, Integer userId) {
+        // 1. 查询用户是否存在
+        Users user = usersMapper.selectById(userId);
+        if (user == null) {
+            throw new RuntimeException("用户不存在");
+        }
+        
+        // 2. 更新用户的isMatchmaker为1
+        user.setIsMatchmaker(1);
+        int userUpdateResult = usersMapper.updateById(user);
+        if (userUpdateResult <= 0) {
+            throw new RuntimeException("更新用户红娘状态失败");
+        }
+        
+        // 3. 更新申请记录的更新人和更新时间
+        MarrApply apply = this.getById(applyId);
+        if (apply != null) {
+            apply.setUpdateTime(new Date());
+            // 这里可以从当前登录用户获取,暂时设置为"系统"
+            apply.setUpdateMan("系统");
+            this.updateById(apply);
+        }
+        
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean delete(Long applyId) {
+        return this.removeById(applyId);
+    }
+}
+
+
+
+

+ 46 - 0
service/admin/src/main/resources/com/zhentao/mapper/MarrApplyMapper.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zhentao.mapper.MarrApplyMapper">
+
+    <resultMap id="BaseResultMap" type="com.zhentao.entity.MarrApply">
+            <id property="applyId" column="apply_id" />
+            <result property="userId" column="user_id" />
+            <result property="name" column="name" />
+            <result property="phone" column="phone" />
+            <result property="email" column="email" />
+            <result property="age" column="age" />
+            <result property="gender" column="gender" />
+            <result property="area" column="area" />
+            <result property="experience" column="experience" />
+            <result property="serverTime" column="server_time" />
+            <result property="introduction" column="introduction" />
+            <result property="createTime" column="create_time" />
+            <result property="createMan" column="create_man" />
+            <result property="updateTime" column="update_time" />
+            <result property="updateMan" column="update_man" />
+            <result property="status" column="status" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        apply_id,user_id,name,phone,email,age,
+        gender,area,experience,server_time,introduction,
+        create_time,create_man,update_time,update_man,status
+    </sql>
+
+    <select id="selectPageByCondition" resultMap="BaseResultMap">
+        SELECT
+        <include refid="Base_Column_List"/>
+        FROM marr_apply
+        <where>
+            <if test="name != null and name != ''">
+                AND name LIKE CONCAT('%', #{name}, '%')
+            </if>
+            <if test="phone != null and phone != ''">
+                AND phone LIKE CONCAT('%', #{phone}, '%')
+            </if>
+        </where>
+        ORDER BY create_time DESC
+    </select>
+</mapper>