Просмотр исходного кода

feat: 添加关注和取消关注标段的接口,优化获取关注列表和检查关注状态的逻辑

caipin 1 месяц назад
Родитель
Сommit
a1e2f2fadc
4 измененных файлов с 256 добавлено и 17 удалено
  1. 74 0
      app/controller/weapp_attention_controller.js
  2. 4 0
      app/router.js
  3. 37 17
      app/service/tender.js
  4. 141 0
      app/service/weapp_attention.js

+ 74 - 0
app/controller/weapp_attention_controller.js

@@ -0,0 +1,74 @@
+'use strict';
+
+module.exports = app => {
+    class WeappAttentionController extends app.BaseController {
+        // 关注标段
+        async follow() {
+            const { ctx } = this;
+            try {
+                const { tenderIds } = ctx.request.body;
+                if (!tenderIds || !Array.isArray(tenderIds) || tenderIds.length === 0) {
+                    ctx.body = { err: 1, msg: '参数错误:请提供标段ID数组', data: null };
+                    return;
+                }
+                const result = await ctx.service.weappAttention.followSections(tenderIds, ctx.projectAccount.id);
+                if (result) {
+                    ctx.body = { err: 0, msg: '关注成功', data: null };
+                } else {
+                    ctx.body = { err: 1, msg: '关注失败', data: null };
+                }
+            } catch (error) {
+                ctx.body = this.ajaxErrorBody(error, '关注操作失败');
+            }
+        }
+
+        // 取消关注标段
+        async unfollow() {
+            const { ctx } = this;
+            try {
+                const { tenderIds } = ctx.request.body;
+                if (!tenderIds || !Array.isArray(tenderIds) || tenderIds.length === 0) {
+                    ctx.body = { err: 1, msg: '参数错误:请提供标段ID数组', data: null };
+                    return;
+                }
+                const result = await ctx.service.weappAttention.unfollowSections(tenderIds, ctx.projectAccount.id);
+                if (result) {
+                    ctx.body = { err: 0, msg: '取消关注成功', data: null };
+                } else {
+                    ctx.body = { err: 1, msg: '取消关注失败', data: null };
+                }
+            } catch (error) {
+                ctx.body = this.ajaxErrorBody(error, '取消关注操作失败');
+            }
+        }
+
+        // 获取用户关注的标段列表
+        async followedList() {
+            const { ctx } = this;
+            try {
+                const result = await ctx.service.weappAttention.getFollowedSections(ctx.projectAccount.id);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (error) {
+                ctx.body = this.ajaxErrorBody(error, '获取关注列表失败');
+            }
+        }
+
+        // 检查用户是否关注了某个标段
+        async checkFollowing() {
+            const { ctx } = this;
+            try {
+                const { tenderId } = ctx.query;
+                if (!tenderId) {
+                    ctx.body = { err: 1, msg: '参数错误:请提供标段ID', data: null };
+                    return;
+                }
+                const isFollowing = await ctx.service.weappAttention.isFollowingSection(ctx.projectAccount.id, tenderId);
+                ctx.body = { err: 0, msg: '', data: { following: isFollowing } };
+            } catch (error) {
+                ctx.body = this.ajaxErrorBody(error, '检查关注状态失败');
+            }
+        }
+
+    }
+    return WeappAttentionController;
+};

+ 4 - 0
app/router.js

@@ -1243,4 +1243,8 @@ module.exports = app => {
     app.get('/wx/weapp/dashboard', weappAuth, 'weappDashboardController.workspace');
     app.get('/wx/weapp/subp/list', weappAuth, 'weappSubpController.subProjectList');
     app.get('/wx/weapp/subp/detail', weappAuth, 'weappSubpController.subProjectDetail');
+    app.post('/wx/weapp/attention/follow', weappAuth, 'weappAttentionController.follow');
+    app.post('/wx/weapp/attention/unfollow', weappAuth, 'weappAttentionController.unfollow');
+    app.get('/wx/weapp/attention/list', weappAuth, 'weappAttentionController.followedList');
+    app.get('/wx/weapp/attention/check', weappAuth, 'weappAttentionController.checkFollowing');
 };

+ 37 - 17
app/service/tender.js

@@ -171,17 +171,17 @@ module.exports = app => {
                     // 未参与,但可见的标段
                     ') ORDER BY CONVERT(t.`name` USING GBK) ASC';
                 sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, subProject.id, session.sessionUser.accountId,
-                    this.ctx.service.ledgerAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.stageAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.auditAss.tableName, session.sessionUser.accountId,
-                    this.ctx.service.settleAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.phasePayAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.changeAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.reviseAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.materialAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.advanceAudit.tableName, session.sessionUser.accountId,
-                    this.ctx.service.tenderTourist.tableName, session.sessionUser.accountId,
-                    this.ctx.service.tenderAss.tableName, session.sessionUser.accountId,
+                this.ctx.service.ledgerAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.stageAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.auditAss.tableName, session.sessionUser.accountId,
+                this.ctx.service.settleAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.phasePayAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.changeAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.reviseAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.materialAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.advanceAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.tenderTourist.tableName, session.sessionUser.accountId,
+                this.ctx.service.tenderAss.tableName, session.sessionUser.accountId,
                 ];
             }
             const list = await this.db.query(sql, sqlParam);
@@ -262,7 +262,7 @@ module.exports = app => {
         }
 
         async getManageTenderList(projectId) {
-            return await this.ctx.service.tender.getAllDataByCondition({ where: { project_id: projectId }});
+            return await this.ctx.service.tender.getAllDataByCondition({ where: { project_id: projectId } });
         }
 
         /**
@@ -359,13 +359,13 @@ module.exports = app => {
                 const result = await conn.update(this.tableName, rowData);
                 await conn.commit();
                 return result.affectedRows > 0;
-            } catch(err) {
+            } catch (err) {
                 await conn.rollback();
                 throw err;
             }
         }
 
-        async batchUpdate (data) {
+        async batchUpdate(data) {
             const validFields = ['filter_budget', 'filter_fund'];
             const updateData = [];
             for (const d of data) {
@@ -589,7 +589,7 @@ module.exports = app => {
         }
 
         async saveApiRela(tid, updateData) {
-            await this.db.update(this.tableName, updateData, {where: { id: tid } });
+            await this.db.update(this.tableName, updateData, { where: { id: tid } });
         }
 
         async saveTenderData(tid, updateData) {
@@ -617,6 +617,26 @@ module.exports = app => {
             return list;
         }
 
+        async getDataByIds(ids, columns = commonQueryColumns) {
+            if (!ids || !Array.isArray(ids) || ids.length === 0) {
+                return [];
+            }
+
+            // 构建IN查询
+            const placeholders = ids.map(() => '?').join(',');
+            const sql = `SELECT ${columns.join(', ')} FROM ${this.tableName} WHERE id IN (${placeholders})`;
+            const result = await this.db.query(sql, ids);
+
+            // 处理category字段,如果存在的话
+            if (this._.includes(columns, 'category')) {
+                for (const item of result) {
+                    item.category = item.category && item.category !== '' ? JSON.parse(item.category) : null;
+                }
+            }
+
+            return result;
+        }
+
         /**
          * 获取你所参与的施工标段的列表
          *
@@ -653,7 +673,7 @@ module.exports = app => {
                     ' t.id IN ( SELECT ca.`tid` FROM ?? As ca WHERE ca.`uid` = ?)' +
                     ' ORDER BY CONVERT(t.`name` USING GBK) ASC';
                 sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, session.sessionProject.id, this.ctx.subProject.id,
-                    this.ctx.service.constructionAudit.tableName, session.sessionUser.accountId,
+                this.ctx.service.constructionAudit.tableName, session.sessionUser.accountId,
                 ];
             }
             const list = await this.db.query(sql, sqlParam);
@@ -700,7 +720,7 @@ module.exports = app => {
                     ' t.id IN ( SELECT ca.`tid` FROM ?? As ca WHERE ca.`uid` = ?)' +
                     ' AND t.`spid` = ? ORDER BY CONVERT(t.`name` USING GBK) ASC';
                 sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, session.sessionProject.id,
-                    this.ctx.service.contractAudit.tableName, session.sessionUser.accountId, this.ctx.subProject.id,
+                this.ctx.service.contractAudit.tableName, session.sessionUser.accountId, this.ctx.subProject.id,
                 ];
             }
             const list = await this.db.query(sql, sqlParam);

+ 141 - 0
app/service/weapp_attention.js

@@ -0,0 +1,141 @@
+'use strict';
+
+module.exports = app => {
+    class WeappAttentionService extends app.BaseService {
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'weapp_attention';
+        }
+
+        /**
+         * 关注标段
+         * @param {Array} tenderIds - 标段ID数组
+         * @param {Number} userId - 用户ID
+         * @return {Boolean} - 是否成功
+         */
+        async followSections(tenderIds, userId) {
+            const conn = this.db;
+            try {
+                await conn.beginTransaction();
+                for (const tenderId of tenderIds) {
+                    const existingRecord = await this.getDataByCondition({
+                        project_account_id: userId,
+                        tender_id: tenderId
+                    });
+
+                    if (existingRecord) {
+                        if (existingRecord.status === 0) {
+                            await conn.update(this.tableName, {
+                                id: existingRecord.id,
+                                status: 1,
+                                create_time: this.app.formatDate(new Date())
+                            });
+                        }
+                    } else {
+                        await conn.insert(this.tableName, {
+                            project_account_id: userId,
+                            tender_id: tenderId,
+                            status: 1,
+                            create_time: this.app.formatDate(new Date())
+                        });
+                    }
+                }
+                await conn.commit();
+                return true;
+            } catch (error) {
+                await conn.rollback();
+                this.ctx.throw(500, error.message);
+                return false;
+            }
+        }
+
+        /**
+         * 取消关注标段
+         * @param {Array} tenderIds - 标段ID数组
+         * @param {Number} userId - 用户ID
+         * @return {Boolean} - 是否成功
+         */
+        async unfollowSections(tenderIds, userId) {
+            const conn = this.db;
+            try {
+                await conn.beginTransaction();
+
+                for (const tenderId of tenderIds) {
+                    await conn.update(this.tableName, {
+                        project_account_id: userId,
+                        tender_id: tenderId,
+                    }, {
+                        status: 0
+                    });
+                }
+                await conn.commit();
+                return true;
+            } catch (error) {
+                await conn.rollback();
+                this.ctx.throw(500, error.message);
+                return false;
+            }
+        }
+
+        /**
+         * 获取用户关注的标段列表
+         * @param {Number} userId - 用户ID
+         * @return {Array} - 关注的标段列表
+         */
+        async getFollowedSections(userId) {
+            const attentionRecords = await this.getAllDataByCondition({
+                where: {
+                    project_account_id: userId,
+                    status: 1
+                },
+                orders: [['create_time', 'desc']]
+            });
+            if (!attentionRecords || attentionRecords.length === 0) {
+                return [];
+            }
+            const tenderIds = attentionRecords.map(record => record.tender_id);
+            const tenders = await this.ctx.service.tender.getDataByIds(tenderIds);
+            const spIds = [...new Set(tenders.filter(tender => tender.spid).map(tender => tender.spid))];
+            let subProjects = {};
+            if (spIds.length > 0) {
+                const subProjectList = await this.ctx.service.subProject.getAllDataByCondition({
+                    where: {
+                        id: spIds
+                    }
+                });
+                subProjects = subProjectList.reduce((acc, subProject) => {
+                    acc[subProject.id] = subProject;
+                    return acc;
+                }, {});
+            }
+            const result = attentionRecords.map(record => {
+                const tender = tenders.find(t => t.id === record.tender_id);
+                const subProject = tender && tender.spid ? subProjects[tender.spid] : null;
+                return {
+                    ...record,
+                    tender_info: tender || null,
+                    sub_project_info: subProject || null
+                };
+            });
+
+            return result;
+        }
+
+        /**
+         * 检查用户是否关注了某个标段
+         * @param {Number} userId - 用户ID
+         * @param {Number} tenderId - 标段ID
+         * @return {Boolean} - 是否关注
+         */
+        async isFollowingSection(userId, tenderId) {
+            const record = await this.getDataByCondition({
+                project_account_id: userId,
+                tender_id: tenderId,
+                status: 1
+            });
+            return !!record;
+        }
+    }
+
+    return WeappAttentionService;
+};