feat(publicity): 公示页支持/执行意向 (匿名提交 + 管理审核)
- 新增 biz_publicity_support_intent / biz_publicity_execution_intent 两张独立表 (与已登录视角的 biz_support_intent / biz_execution_intent 解耦, 避免匿名数据污染强绑表) - 后端 BizPublicityIntentController: 公开提交 + 公开查重 (按 project_id+phone+source) + 管理 CRUD 已登录直接取 user_id, 未登录但 phone 命中 sys_user 仍自动关联 user_id (不回强制登录) - /business/publicity/** 加 Spring Security permitAll - 前端 PublicityDetail.vue: 右侧 2 个意向按钮 (已登录/匿名都弹 dialog 填 5 字段), 已提交状态用 hasPublicityIntent 按 phonenumber 持久化查回 - 重写 manager/SupportIntent.vue + manager/ExecIntent.vue: 列表/筛选/CSV导出/状态变更/批量删除
This commit is contained in:
+208
@@ -0,0 +1,208 @@
|
|||||||
|
package com.ruoyi.business.controller;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.ruoyi.common.annotation.Log;
|
||||||
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.business.domain.BizProject;
|
||||||
|
import com.ruoyi.business.domain.BizPublicityExecutionIntent;
|
||||||
|
import com.ruoyi.business.domain.BizPublicitySupportIntent;
|
||||||
|
import com.ruoyi.business.service.IBizProjectService;
|
||||||
|
import com.ruoyi.business.service.IBizPublicityExecutionIntentService;
|
||||||
|
import com.ruoyi.business.service.IBizPublicitySupportIntentService;
|
||||||
|
import com.ruoyi.system.mapper.SysUserMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公示页意向 Controller (匿名 + 管理后台共用)
|
||||||
|
*
|
||||||
|
* 公开端点 (公开门户 + 匿名访客可调):
|
||||||
|
* - POST /business/publicity/supportIntent 提交支持意向
|
||||||
|
* - POST /business/publicity/executionIntent 提交执行意向
|
||||||
|
* - GET /business/publicity/hasIntent 查"是否已提交" (按 projectId + phone + type)
|
||||||
|
*
|
||||||
|
* 管理端点 (manager / admin 后台列表, 复用通用 /list /{id} / POST / PUT / DELETE):
|
||||||
|
* - /business/publicitySupportIntent/...
|
||||||
|
* - /business/publicityExecutionIntent/...
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class BizPublicityIntentController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired private IBizProjectService bizProjectService;
|
||||||
|
@Autowired private IBizPublicitySupportIntentService supportIntentService;
|
||||||
|
@Autowired private IBizPublicityExecutionIntentService executionIntentService;
|
||||||
|
@Autowired private SysUserMapper sysUserMapper;
|
||||||
|
|
||||||
|
private static final String SOURCE_PUBLICITY = "publicity";
|
||||||
|
|
||||||
|
// ============== 公开端点: 提交 ==============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交支持意向 (公开)
|
||||||
|
* POST /business/publicity/supportIntent
|
||||||
|
* body: { projectId, name, phone, workUnit, department?, position? }
|
||||||
|
* 已登录自动回填 user_id
|
||||||
|
*/
|
||||||
|
@Log(title = "公示页-支持意向", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/business/publicity/supportIntent")
|
||||||
|
public AjaxResult submitSupportIntent(@RequestBody BizPublicitySupportIntent intent) {
|
||||||
|
return doSubmit(intent, supportIntentService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交执行意向 (公开)
|
||||||
|
*/
|
||||||
|
@Log(title = "公示页-执行意向", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/business/publicity/executionIntent")
|
||||||
|
public AjaxResult submitExecutionIntent(@RequestBody BizPublicityExecutionIntent intent) {
|
||||||
|
return doSubmit(intent, executionIntentService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 通用提交逻辑 (支持 + 执行 同构) */
|
||||||
|
private <T> AjaxResult doSubmit(T rawIntent, Object service) {
|
||||||
|
// 取通用字段
|
||||||
|
Long projectId = null;
|
||||||
|
String name = null, phone = null, workUnit = null, department = null, position = null;
|
||||||
|
if (rawIntent instanceof BizPublicitySupportIntent) {
|
||||||
|
BizPublicitySupportIntent i = (BizPublicitySupportIntent) rawIntent;
|
||||||
|
projectId = i.getProjectId(); name = i.getName(); phone = i.getPhone();
|
||||||
|
workUnit = i.getWorkUnit(); department = i.getDepartment(); position = i.getPosition();
|
||||||
|
} else if (rawIntent instanceof BizPublicityExecutionIntent) {
|
||||||
|
BizPublicityExecutionIntent i = (BizPublicityExecutionIntent) rawIntent;
|
||||||
|
projectId = i.getProjectId(); name = i.getName(); phone = i.getPhone();
|
||||||
|
workUnit = i.getWorkUnit(); department = i.getDepartment(); position = i.getPosition();
|
||||||
|
}
|
||||||
|
if (projectId == null) return error("projectId 不能为空");
|
||||||
|
if (name == null || name.trim().isEmpty()) return error("姓名不能为空");
|
||||||
|
if (phone == null || phone.trim().isEmpty()) return error("手机号不能为空");
|
||||||
|
if (workUnit == null || workUnit.trim().isEmpty()) return error("工作单位不能为空");
|
||||||
|
// 反查项目 no/name 写冗余
|
||||||
|
BizProject proj = bizProjectService.getById(String.valueOf(projectId));
|
||||||
|
if (proj == null) return error("项目不存在");
|
||||||
|
// 查重 (按 project_id + phone + source)
|
||||||
|
Object dup;
|
||||||
|
if (service instanceof IBizPublicitySupportIntentService) {
|
||||||
|
dup = ((IBizPublicitySupportIntentService) service).findDuplicate(projectId, phone, SOURCE_PUBLICITY);
|
||||||
|
} else {
|
||||||
|
dup = ((IBizPublicityExecutionIntentService) service).findDuplicate(projectId, phone, SOURCE_PUBLICITY);
|
||||||
|
}
|
||||||
|
if (dup != null) return error("您已提交过该意向");
|
||||||
|
// 回填 user_id + createBy:
|
||||||
|
// 1) 已登录直接取当前用户
|
||||||
|
// 2) 未登录但 phone 能匹配到 sys_user → 仍回填 userId (账号自动关联, 不需要登录)
|
||||||
|
// 3) 完全匿名 → 两者都为空
|
||||||
|
String createBy = null;
|
||||||
|
Long userId = null;
|
||||||
|
try {
|
||||||
|
if (SecurityUtils.getUsername() != null && !"anonymous".equals(SecurityUtils.getUsername())) {
|
||||||
|
createBy = SecurityUtils.getUsername();
|
||||||
|
userId = SecurityUtils.getUserId();
|
||||||
|
}
|
||||||
|
} catch (Exception ignore) { /* 匿名 */ }
|
||||||
|
if (userId == null && phone != null && !phone.isEmpty()) {
|
||||||
|
try {
|
||||||
|
com.ruoyi.common.core.domain.entity.SysUser u = sysUserMapper.checkPhoneUnique(phone);
|
||||||
|
if (u != null && u.getUserId() != null) {
|
||||||
|
userId = u.getUserId();
|
||||||
|
// 匿名场景下也补一下 createBy (虽然表里没强制要求, 但便于审计)
|
||||||
|
if (createBy == null) createBy = u.getUserName();
|
||||||
|
}
|
||||||
|
} catch (Exception ignore) { /* 表不存在等 */ }
|
||||||
|
}
|
||||||
|
// 写入
|
||||||
|
int n;
|
||||||
|
if (rawIntent instanceof BizPublicitySupportIntent) {
|
||||||
|
BizPublicitySupportIntent i = (BizPublicitySupportIntent) rawIntent;
|
||||||
|
i.setProjectNo(proj.getProjectNo());
|
||||||
|
i.setProjectName(proj.getProjectName());
|
||||||
|
i.setSource(SOURCE_PUBLICITY);
|
||||||
|
i.setIntentStatus("待审核");
|
||||||
|
i.setUserId(userId);
|
||||||
|
i.setCreateBy(createBy);
|
||||||
|
n = supportIntentService.insert(i);
|
||||||
|
return n > 0 ? success(i) : error("提交失败");
|
||||||
|
} else {
|
||||||
|
BizPublicityExecutionIntent i = (BizPublicityExecutionIntent) rawIntent;
|
||||||
|
i.setProjectNo(proj.getProjectNo());
|
||||||
|
i.setProjectName(proj.getProjectName());
|
||||||
|
i.setSource(SOURCE_PUBLICITY);
|
||||||
|
i.setIntentStatus("待审核");
|
||||||
|
i.setUserId(userId);
|
||||||
|
i.setCreateBy(createBy);
|
||||||
|
n = executionIntentService.insert(i);
|
||||||
|
return n > 0 ? success(i) : error("提交失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 持久化"已提交"查询 (公开)
|
||||||
|
* GET /business/publicity/hasIntent?projectId=&phone=&type=support|execution
|
||||||
|
* 按 (project_id, phone, source='publicity') 查重
|
||||||
|
*/
|
||||||
|
@GetMapping("/business/publicity/hasIntent")
|
||||||
|
public AjaxResult hasIntent(@RequestParam("projectId") Long projectId,
|
||||||
|
@RequestParam("phone") String phone,
|
||||||
|
@RequestParam("type") String type) {
|
||||||
|
if (projectId == null || phone == null || phone.isEmpty()) return success(false);
|
||||||
|
boolean exists;
|
||||||
|
if ("execution".equalsIgnoreCase(type)) {
|
||||||
|
exists = executionIntentService.findDuplicate(projectId, phone, SOURCE_PUBLICITY) != null;
|
||||||
|
} else {
|
||||||
|
// 默认 support
|
||||||
|
exists = supportIntentService.findDuplicate(projectId, phone, SOURCE_PUBLICITY) != null;
|
||||||
|
}
|
||||||
|
return success(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============== 管理端点: 列表 + CRUD (manager / admin 后台) ==============
|
||||||
|
|
||||||
|
/** 支持意向列表 (分页, 与现有 /business/supportIntent/list 一致格式) */
|
||||||
|
@GetMapping("/business/publicitySupportIntent/list")
|
||||||
|
public TableDataInfo listSupport(BizPublicitySupportIntent intent) {
|
||||||
|
startPage();
|
||||||
|
List<BizPublicitySupportIntent> list = supportIntentService.selectList(intent);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
@GetMapping("/business/publicitySupportIntent/{intentId}")
|
||||||
|
public AjaxResult getSupport(@PathVariable("intentId") Long intentId) {
|
||||||
|
return success(supportIntentService.getById(intentId));
|
||||||
|
}
|
||||||
|
@Log(title = "公示页-支持意向", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/business/publicitySupportIntent")
|
||||||
|
public AjaxResult editSupport(@RequestBody BizPublicitySupportIntent intent) {
|
||||||
|
try { intent.setUpdateBy(SecurityUtils.getUsername()); } catch (Exception ignore) {}
|
||||||
|
return toAjax(supportIntentService.updateByPrimaryKey(intent));
|
||||||
|
}
|
||||||
|
@Log(title = "公示页-支持意向", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/business/publicitySupportIntent/{ids}")
|
||||||
|
public AjaxResult removeSupport(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(supportIntentService.deleteByPrimaryKeys(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 执行意向列表 */
|
||||||
|
@GetMapping("/business/publicityExecutionIntent/list")
|
||||||
|
public TableDataInfo listExecution(BizPublicityExecutionIntent intent) {
|
||||||
|
startPage();
|
||||||
|
List<BizPublicityExecutionIntent> list = executionIntentService.selectList(intent);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
@GetMapping("/business/publicityExecutionIntent/{intentId}")
|
||||||
|
public AjaxResult getExecution(@PathVariable("intentId") Long intentId) {
|
||||||
|
return success(executionIntentService.getById(intentId));
|
||||||
|
}
|
||||||
|
@Log(title = "公示页-执行意向", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/business/publicityExecutionIntent")
|
||||||
|
public AjaxResult editExecution(@RequestBody BizPublicityExecutionIntent intent) {
|
||||||
|
try { intent.setUpdateBy(SecurityUtils.getUsername()); } catch (Exception ignore) {}
|
||||||
|
return toAjax(executionIntentService.updateByPrimaryKey(intent));
|
||||||
|
}
|
||||||
|
@Log(title = "公示页-执行意向", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/business/publicityExecutionIntent/{ids}")
|
||||||
|
public AjaxResult removeExecution(@PathVariable Long[] ids) {
|
||||||
|
return toAjax(executionIntentService.deleteByPrimaryKeys(ids));
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
package com.ruoyi.business.domain;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公示页-执行意向 (匿名快照, 与 sys_user 解耦)
|
||||||
|
* 数据源: /publicity/:projectId 页面 "表达执行意向" 按钮
|
||||||
|
* 与 biz_execution_intent (旧表, 已登录专家报名流程) 语义不同, 物理表独立
|
||||||
|
*/
|
||||||
|
public class BizPublicityExecutionIntent extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
/** intent_id */
|
||||||
|
private Long intentId;
|
||||||
|
/** project_id (biz_project.project_id) */
|
||||||
|
@Excel(name = "project_id")
|
||||||
|
private Long projectId;
|
||||||
|
/** project_no (冗余) */
|
||||||
|
@Excel(name = "project_no")
|
||||||
|
private String projectNo;
|
||||||
|
/** project_name (冗余) */
|
||||||
|
@Excel(name = "project_name")
|
||||||
|
private String projectName;
|
||||||
|
/** user_id (已登录时回填 sys_user.user_id, 未登录 NULL) */
|
||||||
|
@Excel(name = "user_id")
|
||||||
|
private Long userId;
|
||||||
|
/** name */
|
||||||
|
@Excel(name = "name")
|
||||||
|
private String name;
|
||||||
|
/** phone */
|
||||||
|
@Excel(name = "phone")
|
||||||
|
private String phone;
|
||||||
|
/** work_unit 工作单位名称 */
|
||||||
|
@Excel(name = "work_unit")
|
||||||
|
private String workUnit;
|
||||||
|
/** department 部门 */
|
||||||
|
@Excel(name = "department")
|
||||||
|
private String department;
|
||||||
|
/** position 职务 */
|
||||||
|
@Excel(name = "position")
|
||||||
|
private String position;
|
||||||
|
/** source 来源 publicity=公示页 */
|
||||||
|
@Excel(name = "source")
|
||||||
|
private String source;
|
||||||
|
/** intent_status 状态 (待审核/已采纳/已拒绝) */
|
||||||
|
@Excel(name = "intent_status")
|
||||||
|
private String intentStatus;
|
||||||
|
/** remark 备注 */
|
||||||
|
private String remark;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
public Long getIntentId() { return intentId; }
|
||||||
|
public void setIntentId(Long intentId) { this.intentId = intentId; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public String getProjectNo() { return projectNo; }
|
||||||
|
public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
|
||||||
|
public String getProjectName() { return projectName; }
|
||||||
|
public void setProjectName(String projectName) { this.projectName = projectName; }
|
||||||
|
public Long getUserId() { return userId; }
|
||||||
|
public void setUserId(Long userId) { this.userId = userId; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
public String getPhone() { return phone; }
|
||||||
|
public void setPhone(String phone) { this.phone = phone; }
|
||||||
|
public String getWorkUnit() { return workUnit; }
|
||||||
|
public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
|
||||||
|
public String getDepartment() { return department; }
|
||||||
|
public void setDepartment(String department) { this.department = department; }
|
||||||
|
public String getPosition() { return position; }
|
||||||
|
public void setPosition(String position) { this.position = position; }
|
||||||
|
public String getSource() { return source; }
|
||||||
|
public void setSource(String source) { this.source = source; }
|
||||||
|
public String getIntentStatus() { return intentStatus; }
|
||||||
|
public void setIntentStatus(String intentStatus) { this.intentStatus = intentStatus; }
|
||||||
|
public String getRemark() { return remark; }
|
||||||
|
public void setRemark(String remark) { this.remark = remark; }
|
||||||
|
public Date getCreateTime() { return createTime; }
|
||||||
|
public void setCreateTime(Date createTime) { this.createTime = createTime; }
|
||||||
|
public Date getUpdateTime() { return updateTime; }
|
||||||
|
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
package com.ruoyi.business.domain;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公示页-支持意向 (匿名快照, 与 sys_user 解耦)
|
||||||
|
* 数据源: /publicity/:projectId 页面 "表达支持意向" 按钮
|
||||||
|
* 与 biz_support_intent (旧表, 已登录用户流程) 语义不同, 物理表独立
|
||||||
|
*/
|
||||||
|
public class BizPublicitySupportIntent extends BaseEntity {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
/** intent_id */
|
||||||
|
private Long intentId;
|
||||||
|
/** project_id (biz_project.project_id) */
|
||||||
|
@Excel(name = "project_id")
|
||||||
|
private Long projectId;
|
||||||
|
/** project_no (冗余) */
|
||||||
|
@Excel(name = "project_no")
|
||||||
|
private String projectNo;
|
||||||
|
/** project_name (冗余) */
|
||||||
|
@Excel(name = "project_name")
|
||||||
|
private String projectName;
|
||||||
|
/** user_id (已登录时回填 sys_user.user_id, 未登录 NULL) */
|
||||||
|
@Excel(name = "user_id")
|
||||||
|
private Long userId;
|
||||||
|
/** name */
|
||||||
|
@Excel(name = "name")
|
||||||
|
private String name;
|
||||||
|
/** phone */
|
||||||
|
@Excel(name = "phone")
|
||||||
|
private String phone;
|
||||||
|
/** work_unit 工作单位名称 */
|
||||||
|
@Excel(name = "work_unit")
|
||||||
|
private String workUnit;
|
||||||
|
/** department 部门 */
|
||||||
|
@Excel(name = "department")
|
||||||
|
private String department;
|
||||||
|
/** position 职务 */
|
||||||
|
@Excel(name = "position")
|
||||||
|
private String position;
|
||||||
|
/** source 来源 publicity=公示页 */
|
||||||
|
@Excel(name = "source")
|
||||||
|
private String source;
|
||||||
|
/** intent_status 状态 (待审核/已采纳/已拒绝) */
|
||||||
|
@Excel(name = "intent_status")
|
||||||
|
private String intentStatus;
|
||||||
|
/** remark 备注 */
|
||||||
|
private String remark;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime;
|
||||||
|
public Long getIntentId() { return intentId; }
|
||||||
|
public void setIntentId(Long intentId) { this.intentId = intentId; }
|
||||||
|
public Long getProjectId() { return projectId; }
|
||||||
|
public void setProjectId(Long projectId) { this.projectId = projectId; }
|
||||||
|
public String getProjectNo() { return projectNo; }
|
||||||
|
public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
|
||||||
|
public String getProjectName() { return projectName; }
|
||||||
|
public void setProjectName(String projectName) { this.projectName = projectName; }
|
||||||
|
public Long getUserId() { return userId; }
|
||||||
|
public void setUserId(Long userId) { this.userId = userId; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
public String getPhone() { return phone; }
|
||||||
|
public void setPhone(String phone) { this.phone = phone; }
|
||||||
|
public String getWorkUnit() { return workUnit; }
|
||||||
|
public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
|
||||||
|
public String getDepartment() { return department; }
|
||||||
|
public void setDepartment(String department) { this.department = department; }
|
||||||
|
public String getPosition() { return position; }
|
||||||
|
public void setPosition(String position) { this.position = position; }
|
||||||
|
public String getSource() { return source; }
|
||||||
|
public void setSource(String source) { this.source = source; }
|
||||||
|
public String getIntentStatus() { return intentStatus; }
|
||||||
|
public void setIntentStatus(String intentStatus) { this.intentStatus = intentStatus; }
|
||||||
|
public String getRemark() { return remark; }
|
||||||
|
public void setRemark(String remark) { this.remark = remark; }
|
||||||
|
public Date getCreateTime() { return createTime; }
|
||||||
|
public void setCreateTime(Date createTime) { this.createTime = createTime; }
|
||||||
|
public Date getUpdateTime() { return updateTime; }
|
||||||
|
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.ruoyi.business.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.business.domain.BizPublicityExecutionIntent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公示页-执行意向 Mapper
|
||||||
|
*/
|
||||||
|
public interface BizPublicityExecutionIntentMapper {
|
||||||
|
BizPublicityExecutionIntent selectByPrimaryKey(Long intentId);
|
||||||
|
List<BizPublicityExecutionIntent> selectList(BizPublicityExecutionIntent entity);
|
||||||
|
/** 查重: 按 (project_id, phone, source) 已存在则返回记录, 否则 null */
|
||||||
|
BizPublicityExecutionIntent selectDuplicate(BizPublicityExecutionIntent entity);
|
||||||
|
int insert(BizPublicityExecutionIntent entity);
|
||||||
|
int updateByPrimaryKey(BizPublicityExecutionIntent entity);
|
||||||
|
int deleteByPrimaryKey(Long intentId);
|
||||||
|
int deleteByPrimaryKeys(Long[] intentIds);
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.ruoyi.business.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.business.domain.BizPublicitySupportIntent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公示页-支持意向 Mapper
|
||||||
|
*/
|
||||||
|
public interface BizPublicitySupportIntentMapper {
|
||||||
|
BizPublicitySupportIntent selectByPrimaryKey(Long intentId);
|
||||||
|
List<BizPublicitySupportIntent> selectList(BizPublicitySupportIntent entity);
|
||||||
|
/** 查重: 按 (project_id, phone, source) 已存在则返回记录, 否则 null */
|
||||||
|
BizPublicitySupportIntent selectDuplicate(BizPublicitySupportIntent entity);
|
||||||
|
int insert(BizPublicitySupportIntent entity);
|
||||||
|
int updateByPrimaryKey(BizPublicitySupportIntent entity);
|
||||||
|
int deleteByPrimaryKey(Long intentId);
|
||||||
|
int deleteByPrimaryKeys(Long[] intentIds);
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ruoyi.business.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.business.domain.BizPublicityExecutionIntent;
|
||||||
|
|
||||||
|
public interface IBizPublicityExecutionIntentService {
|
||||||
|
BizPublicityExecutionIntent getById(Long intentId);
|
||||||
|
List<BizPublicityExecutionIntent> selectList(BizPublicityExecutionIntent entity);
|
||||||
|
/** 按 (projectId, phone, source) 查重 */
|
||||||
|
BizPublicityExecutionIntent findDuplicate(Long projectId, String phone, String source);
|
||||||
|
int insert(BizPublicityExecutionIntent entity);
|
||||||
|
int updateByPrimaryKey(BizPublicityExecutionIntent entity);
|
||||||
|
int deleteByPrimaryKey(Long intentId);
|
||||||
|
int deleteByPrimaryKeys(Long[] intentIds);
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ruoyi.business.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.ruoyi.business.domain.BizPublicitySupportIntent;
|
||||||
|
|
||||||
|
public interface IBizPublicitySupportIntentService {
|
||||||
|
BizPublicitySupportIntent getById(Long intentId);
|
||||||
|
List<BizPublicitySupportIntent> selectList(BizPublicitySupportIntent entity);
|
||||||
|
/** 按 (projectId, phone, source) 查重, 已存在返回记录 */
|
||||||
|
BizPublicitySupportIntent findDuplicate(Long projectId, String phone, String source);
|
||||||
|
int insert(BizPublicitySupportIntent entity);
|
||||||
|
int updateByPrimaryKey(BizPublicitySupportIntent entity);
|
||||||
|
int deleteByPrimaryKey(Long intentId);
|
||||||
|
int deleteByPrimaryKeys(Long[] intentIds);
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.ruoyi.business.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.ruoyi.business.domain.BizPublicityExecutionIntent;
|
||||||
|
import com.ruoyi.business.mapper.BizPublicityExecutionIntentMapper;
|
||||||
|
import com.ruoyi.business.service.IBizPublicityExecutionIntentService;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BizPublicityExecutionIntentServiceImpl implements IBizPublicityExecutionIntentService {
|
||||||
|
@Autowired
|
||||||
|
private BizPublicityExecutionIntentMapper mapper;
|
||||||
|
|
||||||
|
@Override public BizPublicityExecutionIntent getById(Long intentId) { return mapper.selectByPrimaryKey(intentId); }
|
||||||
|
@Override public List<BizPublicityExecutionIntent> selectList(BizPublicityExecutionIntent entity) { return mapper.selectList(entity); }
|
||||||
|
@Override public BizPublicityExecutionIntent findDuplicate(Long projectId, String phone, String source) {
|
||||||
|
BizPublicityExecutionIntent q = new BizPublicityExecutionIntent();
|
||||||
|
q.setProjectId(projectId); q.setPhone(phone); q.setSource(source);
|
||||||
|
return mapper.selectDuplicate(q);
|
||||||
|
}
|
||||||
|
@Override public int insert(BizPublicityExecutionIntent entity) { return mapper.insert(entity); }
|
||||||
|
@Override public int updateByPrimaryKey(BizPublicityExecutionIntent entity) { return mapper.updateByPrimaryKey(entity); }
|
||||||
|
@Override public int deleteByPrimaryKey(Long intentId) { return mapper.deleteByPrimaryKey(intentId); }
|
||||||
|
@Override public int deleteByPrimaryKeys(Long[] intentIds) { return mapper.deleteByPrimaryKeys(intentIds); }
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.ruoyi.business.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.ruoyi.business.domain.BizPublicitySupportIntent;
|
||||||
|
import com.ruoyi.business.mapper.BizPublicitySupportIntentMapper;
|
||||||
|
import com.ruoyi.business.service.IBizPublicitySupportIntentService;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BizPublicitySupportIntentServiceImpl implements IBizPublicitySupportIntentService {
|
||||||
|
@Autowired
|
||||||
|
private BizPublicitySupportIntentMapper mapper;
|
||||||
|
|
||||||
|
@Override public BizPublicitySupportIntent getById(Long intentId) { return mapper.selectByPrimaryKey(intentId); }
|
||||||
|
@Override public List<BizPublicitySupportIntent> selectList(BizPublicitySupportIntent entity) { return mapper.selectList(entity); }
|
||||||
|
@Override public BizPublicitySupportIntent findDuplicate(Long projectId, String phone, String source) {
|
||||||
|
BizPublicitySupportIntent q = new BizPublicitySupportIntent();
|
||||||
|
q.setProjectId(projectId); q.setPhone(phone); q.setSource(source);
|
||||||
|
return mapper.selectDuplicate(q);
|
||||||
|
}
|
||||||
|
@Override public int insert(BizPublicitySupportIntent entity) { return mapper.insert(entity); }
|
||||||
|
@Override public int updateByPrimaryKey(BizPublicitySupportIntent entity) { return mapper.updateByPrimaryKey(entity); }
|
||||||
|
@Override public int deleteByPrimaryKey(Long intentId) { return mapper.deleteByPrimaryKey(intentId); }
|
||||||
|
@Override public int deleteByPrimaryKeys(Long[] intentIds) { return mapper.deleteByPrimaryKeys(intentIds); }
|
||||||
|
}
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
<?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.ruoyi.business.mapper.BizPublicityExecutionIntentMapper">
|
||||||
|
<resultMap type="BizPublicityExecutionIntent" id="BizPublicityExecutionIntentResult">
|
||||||
|
<id property="intentId" column="intent_id" />
|
||||||
|
<result property="projectId" column="project_id" />
|
||||||
|
<result property="projectNo" column="project_no" />
|
||||||
|
<result property="projectName" column="project_name" />
|
||||||
|
<result property="userId" column="user_id" />
|
||||||
|
<result property="name" column="name" />
|
||||||
|
<result property="phone" column="phone" />
|
||||||
|
<result property="workUnit" column="work_unit" />
|
||||||
|
<result property="department" column="department" />
|
||||||
|
<result property="position" column="position" />
|
||||||
|
<result property="source" column="source" />
|
||||||
|
<result property="intentStatus" column="intent_status" />
|
||||||
|
<result property="remark" column="remark" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
</resultMap>
|
||||||
|
<sql id="selectFields">
|
||||||
|
select intent_id, project_id, project_no, project_name, user_id, name, phone, work_unit, department, position, source, intent_status, remark, create_by, create_time, update_by, update_time
|
||||||
|
from biz_publicity_execution_intent
|
||||||
|
</sql>
|
||||||
|
<select id="selectByPrimaryKey" resultMap="BizPublicityExecutionIntentResult" parameterType="Long">
|
||||||
|
<include refid="selectFields"/>
|
||||||
|
where intent_id = #{intentId}
|
||||||
|
</select>
|
||||||
|
<select id="selectList" resultMap="BizPublicityExecutionIntentResult" parameterType="BizPublicityExecutionIntent">
|
||||||
|
<include refid="selectFields"/>
|
||||||
|
<where>
|
||||||
|
<if test="projectId != null"> and project_id = #{projectId}</if>
|
||||||
|
<if test="projectNo != null and projectNo != ''"> and project_no = #{projectNo}</if>
|
||||||
|
<if test="projectName != null and projectName != ''"> and project_name like concat('%', #{projectName}, '%')</if>
|
||||||
|
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
|
||||||
|
<if test="phone != null and phone != ''"> and phone = #{phone}</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''"> and work_unit like concat('%', #{workUnit}, '%')</if>
|
||||||
|
<if test="intentStatus != null and intentStatus != ''"> and intent_status = #{intentStatus}</if>
|
||||||
|
<if test="source != null and source != ''"> and source = #{source}</if>
|
||||||
|
</where>
|
||||||
|
order by intent_id desc
|
||||||
|
</select>
|
||||||
|
<!-- 查重 -->
|
||||||
|
<select id="selectDuplicate" resultMap="BizPublicityExecutionIntentResult" parameterType="BizPublicityExecutionIntent">
|
||||||
|
<include refid="selectFields"/>
|
||||||
|
where project_id = #{projectId}
|
||||||
|
and phone = #{phone}
|
||||||
|
and source = #{source}
|
||||||
|
limit 1
|
||||||
|
</select>
|
||||||
|
<insert id="insert" parameterType="BizPublicityExecutionIntent" useGeneratedKeys="true" keyProperty="intentId">
|
||||||
|
insert into biz_publicity_execution_intent
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="intentId != null">intent_id,</if>
|
||||||
|
<if test="projectId != null">project_id,</if>
|
||||||
|
<if test="projectNo != null and projectNo != ''">project_no,</if>
|
||||||
|
<if test="projectName != null and projectName != ''">project_name,</if>
|
||||||
|
<if test="userId != null">user_id,</if>
|
||||||
|
<if test="name != null and name != ''">name,</if>
|
||||||
|
<if test="phone != null and phone != ''">phone,</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''">work_unit,</if>
|
||||||
|
<if test="department != null and department != ''">department,</if>
|
||||||
|
<if test="position != null and position != ''">position,</if>
|
||||||
|
<if test="source != null and source != ''">source,</if>
|
||||||
|
<if test="intentStatus != null and intentStatus != ''">intent_status,</if>
|
||||||
|
<if test="remark != null and remark != ''">remark,</if>
|
||||||
|
<if test="createBy != null and createBy != ''">create_by,</if>
|
||||||
|
create_time,
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="intentId != null">#{intentId},</if>
|
||||||
|
<if test="projectId != null">#{projectId},</if>
|
||||||
|
<if test="projectNo != null and projectNo != ''">#{projectNo},</if>
|
||||||
|
<if test="projectName != null and projectName != ''">#{projectName},</if>
|
||||||
|
<if test="userId != null">#{userId},</if>
|
||||||
|
<if test="name != null and name != ''">#{name},</if>
|
||||||
|
<if test="phone != null and phone != ''">#{phone},</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''">#{workUnit},</if>
|
||||||
|
<if test="department != null and department != ''">#{department},</if>
|
||||||
|
<if test="position != null and position != ''">#{position},</if>
|
||||||
|
<if test="source != null and source != ''">#{source},</if>
|
||||||
|
<if test="intentStatus != null and intentStatus != ''">#{intentStatus},</if>
|
||||||
|
<if test="remark != null and remark != ''">#{remark},</if>
|
||||||
|
<if test="createBy != null and createBy != ''">#{createBy},</if>
|
||||||
|
sysdate(),
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
<update id="updateByPrimaryKey" parameterType="BizPublicityExecutionIntent">
|
||||||
|
update biz_publicity_execution_intent
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="intentStatus != null and intentStatus != ''">intent_status = #{intentStatus},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="name != null and name != ''">name = #{name},</if>
|
||||||
|
<if test="phone != null and phone != ''">phone = #{phone},</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''">work_unit = #{workUnit},</if>
|
||||||
|
<if test="department != null">department = #{department},</if>
|
||||||
|
<if test="position != null">position = #{position},</if>
|
||||||
|
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||||
|
update_time = sysdate(),
|
||||||
|
</trim>
|
||||||
|
where intent_id = #{intentId}
|
||||||
|
</update>
|
||||||
|
<delete id="deleteByPrimaryKey" parameterType="Long">
|
||||||
|
delete from biz_publicity_execution_intent where intent_id = #{intentId}
|
||||||
|
</delete>
|
||||||
|
<delete id="deleteByPrimaryKeys" parameterType="Long">
|
||||||
|
delete from biz_publicity_execution_intent where intent_id in
|
||||||
|
<foreach collection="array" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
<?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.ruoyi.business.mapper.BizPublicitySupportIntentMapper">
|
||||||
|
<resultMap type="BizPublicitySupportIntent" id="BizPublicitySupportIntentResult">
|
||||||
|
<id property="intentId" column="intent_id" />
|
||||||
|
<result property="projectId" column="project_id" />
|
||||||
|
<result property="projectNo" column="project_no" />
|
||||||
|
<result property="projectName" column="project_name" />
|
||||||
|
<result property="userId" column="user_id" />
|
||||||
|
<result property="name" column="name" />
|
||||||
|
<result property="phone" column="phone" />
|
||||||
|
<result property="workUnit" column="work_unit" />
|
||||||
|
<result property="department" column="department" />
|
||||||
|
<result property="position" column="position" />
|
||||||
|
<result property="source" column="source" />
|
||||||
|
<result property="intentStatus" column="intent_status" />
|
||||||
|
<result property="remark" column="remark" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
</resultMap>
|
||||||
|
<sql id="selectFields">
|
||||||
|
select intent_id, project_id, project_no, project_name, user_id, name, phone, work_unit, department, position, source, intent_status, remark, create_by, create_time, update_by, update_time
|
||||||
|
from biz_publicity_support_intent
|
||||||
|
</sql>
|
||||||
|
<select id="selectByPrimaryKey" resultMap="BizPublicitySupportIntentResult" parameterType="Long">
|
||||||
|
<include refid="selectFields"/>
|
||||||
|
where intent_id = #{intentId}
|
||||||
|
</select>
|
||||||
|
<select id="selectList" resultMap="BizPublicitySupportIntentResult" parameterType="BizPublicitySupportIntent">
|
||||||
|
<include refid="selectFields"/>
|
||||||
|
<where>
|
||||||
|
<if test="projectId != null"> and project_id = #{projectId}</if>
|
||||||
|
<if test="projectNo != null and projectNo != ''"> and project_no = #{projectNo}</if>
|
||||||
|
<if test="projectName != null and projectName != ''"> and project_name like concat('%', #{projectName}, '%')</if>
|
||||||
|
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
|
||||||
|
<if test="phone != null and phone != ''"> and phone = #{phone}</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''"> and work_unit like concat('%', #{workUnit}, '%')</if>
|
||||||
|
<if test="intentStatus != null and intentStatus != ''"> and intent_status = #{intentStatus}</if>
|
||||||
|
<if test="source != null and source != ''"> and source = #{source}</if>
|
||||||
|
</where>
|
||||||
|
order by intent_id desc
|
||||||
|
</select>
|
||||||
|
<!-- 查重: 同一项目同一手机号同一来源只能提交一次 -->
|
||||||
|
<select id="selectDuplicate" resultMap="BizPublicitySupportIntentResult" parameterType="BizPublicitySupportIntent">
|
||||||
|
<include refid="selectFields"/>
|
||||||
|
where project_id = #{projectId}
|
||||||
|
and phone = #{phone}
|
||||||
|
and source = #{source}
|
||||||
|
limit 1
|
||||||
|
</select>
|
||||||
|
<insert id="insert" parameterType="BizPublicitySupportIntent" useGeneratedKeys="true" keyProperty="intentId">
|
||||||
|
insert into biz_publicity_support_intent
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="intentId != null">intent_id,</if>
|
||||||
|
<if test="projectId != null">project_id,</if>
|
||||||
|
<if test="projectNo != null and projectNo != ''">project_no,</if>
|
||||||
|
<if test="projectName != null and projectName != ''">project_name,</if>
|
||||||
|
<if test="userId != null">user_id,</if>
|
||||||
|
<if test="name != null and name != ''">name,</if>
|
||||||
|
<if test="phone != null and phone != ''">phone,</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''">work_unit,</if>
|
||||||
|
<if test="department != null and department != ''">department,</if>
|
||||||
|
<if test="position != null and position != ''">position,</if>
|
||||||
|
<if test="source != null and source != ''">source,</if>
|
||||||
|
<if test="intentStatus != null and intentStatus != ''">intent_status,</if>
|
||||||
|
<if test="remark != null and remark != ''">remark,</if>
|
||||||
|
<if test="createBy != null and createBy != ''">create_by,</if>
|
||||||
|
create_time,
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||||
|
<if test="intentId != null">#{intentId},</if>
|
||||||
|
<if test="projectId != null">#{projectId},</if>
|
||||||
|
<if test="projectNo != null and projectNo != ''">#{projectNo},</if>
|
||||||
|
<if test="projectName != null and projectName != ''">#{projectName},</if>
|
||||||
|
<if test="userId != null">#{userId},</if>
|
||||||
|
<if test="name != null and name != ''">#{name},</if>
|
||||||
|
<if test="phone != null and phone != ''">#{phone},</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''">#{workUnit},</if>
|
||||||
|
<if test="department != null and department != ''">#{department},</if>
|
||||||
|
<if test="position != null and position != ''">#{position},</if>
|
||||||
|
<if test="source != null and source != ''">#{source},</if>
|
||||||
|
<if test="intentStatus != null and intentStatus != ''">#{intentStatus},</if>
|
||||||
|
<if test="remark != null and remark != ''">#{remark},</if>
|
||||||
|
<if test="createBy != null and createBy != ''">#{createBy},</if>
|
||||||
|
sysdate(),
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
<update id="updateByPrimaryKey" parameterType="BizPublicitySupportIntent">
|
||||||
|
update biz_publicity_support_intent
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="intentStatus != null and intentStatus != ''">intent_status = #{intentStatus},</if>
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="name != null and name != ''">name = #{name},</if>
|
||||||
|
<if test="phone != null and phone != ''">phone = #{phone},</if>
|
||||||
|
<if test="workUnit != null and workUnit != ''">work_unit = #{workUnit},</if>
|
||||||
|
<if test="department != null">department = #{department},</if>
|
||||||
|
<if test="position != null">position = #{position},</if>
|
||||||
|
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
|
||||||
|
update_time = sysdate(),
|
||||||
|
</trim>
|
||||||
|
where intent_id = #{intentId}
|
||||||
|
</update>
|
||||||
|
<delete id="deleteByPrimaryKey" parameterType="Long">
|
||||||
|
delete from biz_publicity_support_intent where intent_id = #{intentId}
|
||||||
|
</delete>
|
||||||
|
<delete id="deleteByPrimaryKeys" parameterType="Long">
|
||||||
|
delete from biz_publicity_support_intent where intent_id in
|
||||||
|
<foreach collection="array" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
</mapper>
|
||||||
@@ -61,7 +61,7 @@ public class SecurityConfig
|
|||||||
// OSS 文件代理 (PDF/图片内嵌预览, 重写 Content-Disposition 为 inline)
|
// OSS 文件代理 (PDF/图片内嵌预览, 重写 Content-Disposition 为 inline)
|
||||||
.requestMatchers(HttpMethod.GET, "/common/oss/proxy").permitAll()
|
.requestMatchers(HttpMethod.GET, "/common/oss/proxy").permitAll()
|
||||||
// 业务公开门户与注册入口可匿名访问; 字典 active/单查公开, 写操作需登录+权限
|
// 业务公开门户与注册入口可匿名访问; 字典 active/单查公开, 写操作需登录+权限
|
||||||
.requestMatchers("/business/public/**", "/business/auth/**", "/business/sms/**").permitAll()
|
.requestMatchers("/business/public/**", "/business/publicity/**", "/business/auth/**", "/business/sms/**").permitAll()
|
||||||
// 字典 active (只读) + 按 ID 查 公开给前端拉下拉数据
|
// 字典 active (只读) + 按 ID 查 公开给前端拉下拉数据
|
||||||
.requestMatchers(HttpMethod.GET, "/business/dict/department/active", "/business/dict/title/active",
|
.requestMatchers(HttpMethod.GET, "/business/dict/department/active", "/business/dict/title/active",
|
||||||
"/business/dict/department/*", "/business/dict/title/*").permitAll()
|
"/business/dict/department/*", "/business/dict/title/*").permitAll()
|
||||||
|
|||||||
@@ -107,3 +107,40 @@ export const downloadImportTemplate = (unitType) =>
|
|||||||
// 专家导入模板下载
|
// 专家导入模板下载
|
||||||
export const downloadExpertTemplate = () =>
|
export const downloadExpertTemplate = () =>
|
||||||
request.get('/business/expert/importTemplate', { responseType: 'blob' })
|
request.get('/business/expert/importTemplate', { responseType: 'blob' })
|
||||||
|
|
||||||
|
// ========== 公示页意向 (公开匿名提交, 已在登录或未登录时均可调) ==========
|
||||||
|
// 提交支持意向: body { projectId, name, phone, workUnit, department?, position? }
|
||||||
|
export function submitPublicitySupportIntent(data) {
|
||||||
|
return request.post('/business/publicity/supportIntent', data)
|
||||||
|
}
|
||||||
|
// 提交执行意向
|
||||||
|
export function submitPublicityExecutionIntent(data) {
|
||||||
|
return request.post('/business/publicity/executionIntent', data)
|
||||||
|
}
|
||||||
|
// 持久化查重: GET /business/publicity/hasIntent?projectId=&phone=&type=support|execution
|
||||||
|
export function hasPublicityIntent(projectId, phone, type) {
|
||||||
|
return request.get('/business/publicity/hasIntent', { params: { projectId, phone, type } })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 公示页意向 管理端 (manager / admin 后台) ==========
|
||||||
|
// 列表分页 (后端 startPage 模式)
|
||||||
|
export function listPublicitySupportIntent(params) {
|
||||||
|
return request.get('/business/publicitySupportIntent/list', { params })
|
||||||
|
}
|
||||||
|
export function listPublicityExecutionIntent(params) {
|
||||||
|
return request.get('/business/publicityExecutionIntent/list', { params })
|
||||||
|
}
|
||||||
|
// 编辑 (改 intentStatus / remark)
|
||||||
|
export function updatePublicitySupportIntent(data, opts) {
|
||||||
|
return request.put('/business/publicitySupportIntent', data, opts)
|
||||||
|
}
|
||||||
|
export function updatePublicityExecutionIntent(data, opts) {
|
||||||
|
return request.put('/business/publicityExecutionIntent', data, opts)
|
||||||
|
}
|
||||||
|
// 删除 (单/多)
|
||||||
|
export function deletePublicitySupportIntent(ids) {
|
||||||
|
return request.delete(`/business/publicitySupportIntent/${Array.isArray(ids) ? ids.join(',') : ids}`)
|
||||||
|
}
|
||||||
|
export function deletePublicityExecutionIntent(ids) {
|
||||||
|
return request.delete(`/business/publicityExecutionIntent/${Array.isArray(ids) ? ids.join(',') : ids}`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,24 +2,30 @@
|
|||||||
<div class="page-card manager-exec-intent">
|
<div class="page-card manager-exec-intent">
|
||||||
<div class="breadcrumb">首页 / 执行意向</div>
|
<div class="breadcrumb">首页 / 执行意向</div>
|
||||||
|
|
||||||
<!-- ========== 筛选区 (与 People.vue 风格一致) ========== -->
|
<!-- ========== 筛选区 ========== -->
|
||||||
<el-form inline :model="q" class="filter-form">
|
<el-form inline :model="q" class="filter-form">
|
||||||
<el-form-item label="项目编号"><el-input v-model="q.projectNo" clearable /></el-form-item>
|
<el-form-item label="项目编号"><el-input v-model="q.projectNo" clearable /></el-form-item>
|
||||||
<el-form-item label="项目名称"><el-input v-model="q.projectName" clearable /></el-form-item>
|
<el-form-item label="项目名称"><el-input v-model="q.projectName" clearable /></el-form-item>
|
||||||
<el-form-item label="姓名"><el-input v-model="q.name" clearable /></el-form-item>
|
<el-form-item label="姓名"><el-input v-model="q.name" clearable /></el-form-item>
|
||||||
<el-form-item label="工作单位"><el-input v-model="q.workUnit" clearable /></el-form-item>
|
<el-form-item label="工作单位"><el-input v-model="q.workUnit" clearable /></el-form-item>
|
||||||
<el-form-item label="手机号"><el-input v-model="q.phone" clearable /></el-form-item>
|
<el-form-item label="手机号"><el-input v-model="q.phone" clearable /></el-form-item>
|
||||||
<el-form-item label="签约状态">
|
<el-form-item label="审核状态">
|
||||||
<el-select v-model="q.onboardStatus" clearable>
|
<el-select v-model="q.intentStatus" clearable style="width: 130px">
|
||||||
<el-option label="待签约" value="待签约" /><el-option label="已签约" value="已签约" />
|
<el-option label="待审核" value="待审核" />
|
||||||
<el-option label="已拒绝" value="已拒绝" /><el-option label="已退出" value="已退出" />
|
<el-option label="已通过" value="已通过" />
|
||||||
|
<el-option label="已拒绝" value="已拒绝" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item><el-button type="primary" @click="load">查找</el-button><el-button @click="reset">重置</el-button></el-form-item>
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="load">查找</el-button>
|
||||||
|
<el-button @click="reset">重置</el-button>
|
||||||
|
<el-button type="success" @click="exportCsv">导出CSV</el-button>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- ========== 表格 (与 People.vue 风格一致, 无 page-card 包裹) ========== -->
|
<!-- ========== 表格 ========== -->
|
||||||
<el-table :data="rows" v-loading="loading" stripe border>
|
<el-table :data="rows" v-loading="loading" stripe border @selection-change="onSelChange">
|
||||||
|
<el-table-column type="selection" width="46" />
|
||||||
<el-table-column type="index" label="#" width="50" />
|
<el-table-column type="index" label="#" width="50" />
|
||||||
<el-table-column prop="projectNo" label="意向项目编号" width="140" />
|
<el-table-column prop="projectNo" label="意向项目编号" width="140" />
|
||||||
<el-table-column prop="projectName" label="意向项目名称" min-width="180" show-overflow-tooltip />
|
<el-table-column prop="projectName" label="意向项目名称" min-width="180" show-overflow-tooltip />
|
||||||
@@ -28,14 +34,30 @@
|
|||||||
<el-table-column prop="department" label="部门" width="120" />
|
<el-table-column prop="department" label="部门" width="120" />
|
||||||
<el-table-column prop="position" label="职务" width="100" />
|
<el-table-column prop="position" label="职务" width="100" />
|
||||||
<el-table-column prop="phone" label="手机号" width="130" />
|
<el-table-column prop="phone" label="手机号" width="130" />
|
||||||
<el-table-column label="签约状态" width="100">
|
<el-table-column label="账号状态" width="100" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.onboardStatus==='已签约' ? 'success' : row.onboardStatus==='已拒绝' ? 'danger' : row.onboardStatus==='已退出' ? 'info' : 'warning'">{{ row.onboardStatus }}</el-tag>
|
<el-tag :type="row.userId ? 'success' : 'warning'">{{ row.userId ? '存在' : '不存在' }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="审核状态" width="100" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="statusTagType(row.intentStatus)">{{ row.intentStatus || '待审核' }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="createTime" label="创建时间" width="170" />
|
<el-table-column prop="createTime" label="创建时间" width="170" />
|
||||||
|
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button v-if="row.intentStatus !== '已通过'" type="primary" link size="small" @click="changeStatus(row, '已通过')">通过</el-button>
|
||||||
|
<el-button v-if="row.intentStatus !== '已拒绝'" type="danger" link size="small" @click="changeStatus(row, '已拒绝')">拒绝</el-button>
|
||||||
|
<el-button v-if="row.intentStatus !== '待审核'" type="warning" link size="small" @click="changeStatus(row, '待审核')">重置</el-button>
|
||||||
|
<el-button type="danger" link size="small" @click="removeOne(row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="pager">
|
<div class="pager">
|
||||||
|
<div class="pager-left">
|
||||||
|
<el-button type="danger" :disabled="!selected.length" @click="removeBatch">批量删除 ({{ selected.length }})</el-button>
|
||||||
|
</div>
|
||||||
<el-pagination v-model:current-page="page.pageNum" v-model:page-size="page.pageSize" :total="page.total" :page-sizes="[10,20,50]" layout="total, sizes, prev, pager, next, jumper" @current-change="load" @size-change="load" />
|
<el-pagination v-model:current-page="page.pageNum" v-model:page-size="page.pageSize" :total="page.total" :page-sizes="[10,20,50]" layout="total, sizes, prev, pager, next, jumper" @current-change="load" @size-change="load" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,30 +65,109 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { bizList } from '@/api/public'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import {
|
||||||
|
listPublicityExecutionIntent,
|
||||||
|
updatePublicityExecutionIntent,
|
||||||
|
deletePublicityExecutionIntent
|
||||||
|
} from '@/api/public'
|
||||||
|
|
||||||
const q = ref({ projectNo: '', projectName: '', name: '', workUnit: '', phone: '', onboardStatus: '' })
|
const q = ref({ projectNo: '', projectName: '', name: '', workUnit: '', phone: '', intentStatus: '' })
|
||||||
const rows = ref([])
|
const rows = ref([])
|
||||||
|
const selected = ref([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
|
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const { data } = await bizList('executionIntent', { ...q.value, pageNum: page.pageNum, pageSize: page.pageSize })
|
const { data } = await listPublicityExecutionIntent({ ...q.value, pageNum: page.pageNum, pageSize: page.pageSize })
|
||||||
rows.value = data?.rows || []; page.total = data?.total || 0
|
rows.value = data?.rows || []
|
||||||
} catch { rows.value = []; page.total = 0 }
|
page.total = data?.total || 0
|
||||||
finally { loading.value = false }
|
} catch {
|
||||||
|
rows.value = []; page.total = 0
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
q.value = { projectNo: '', projectName: '', name: '', workUnit: '', phone: '', intentStatus: '' }
|
||||||
|
page.pageNum = 1
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelChange(arr) { selected.value = arr }
|
||||||
|
|
||||||
|
function statusTagType(s) {
|
||||||
|
if (s === '已通过') return 'success'
|
||||||
|
if (s === '已拒绝') return 'danger'
|
||||||
|
return 'warning'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeStatus(row, status) {
|
||||||
|
try {
|
||||||
|
await updatePublicityExecutionIntent({ intentId: row.intentId, intentStatus: status }, { __silentError: true })
|
||||||
|
ElMessage.success(`已${status === '已通过' ? '通过' : status === '已拒绝' ? '拒绝' : '重置'}`)
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.msg || '状态变更失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeOne(row) {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`确认删除 ${row.name} 的执行意向?`, '提示', { type: 'warning' })
|
||||||
|
} catch { return }
|
||||||
|
try {
|
||||||
|
await deletePublicityExecutionIntent([row.intentId])
|
||||||
|
ElMessage.success('已删除')
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.msg || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeBatch() {
|
||||||
|
if (!selected.value.length) return
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`确认删除 ${selected.value.length} 条执行意向?`, '提示', { type: 'warning' })
|
||||||
|
} catch { return }
|
||||||
|
try {
|
||||||
|
const ids = selected.value.map(r => r.intentId)
|
||||||
|
await deletePublicityExecutionIntent(ids)
|
||||||
|
ElMessage.success('已删除')
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.msg || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportCsv() {
|
||||||
|
if (!rows.value.length) return ElMessage.warning('当前列表无数据')
|
||||||
|
const headers = ['项目编号', '项目名称', '姓名', '工作单位', '部门', '职务', '手机号', '账号状态', '审核状态', '创建时间']
|
||||||
|
const csvRows = rows.value.map(r => [
|
||||||
|
r.projectNo, r.projectName, r.name, r.workUnit, r.department, r.position,
|
||||||
|
r.phone, r.userId ? '存在' : '不存在', r.intentStatus || '待审核', r.createTime
|
||||||
|
].map(v => `"` + String(v ?? '').replace(/"/g, '""') + `"`).join(','))
|
||||||
|
const csv = '' + [headers.join(','), ...csvRows].join('\r\n')
|
||||||
|
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' })
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url
|
||||||
|
a.download = `执行意向_${new Date().toISOString().slice(0, 10)}.csv`
|
||||||
|
document.body.appendChild(a); a.click(); document.body.removeChild(a)
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
ElMessage.success(`已导出 ${rows.value.length} 条`)
|
||||||
}
|
}
|
||||||
function reset() { q.value = { projectNo:'', projectName:'', name:'', workUnit:'', phone:'', onboardStatus:'' }; page.pageNum = 1; load() }
|
|
||||||
|
|
||||||
onMounted(load)
|
onMounted(load)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 整页面板 (与 People.vue 风格一致) */
|
|
||||||
.manager-exec-intent { padding: 16px; }
|
.manager-exec-intent { padding: 16px; }
|
||||||
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
|
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
|
||||||
.filter-form { margin-bottom: 12px; }
|
.filter-form { margin-bottom: 12px; }
|
||||||
.pager { display: flex; justify-content: flex-end; margin-top: 12px; }
|
.pager { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; }
|
||||||
</style>
|
.pager-left { display: flex; gap: 8px; }
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -2,42 +2,69 @@
|
|||||||
<div class="page-card manager-support-intent">
|
<div class="page-card manager-support-intent">
|
||||||
<div class="breadcrumb">首页 / 支持意向</div>
|
<div class="breadcrumb">首页 / 支持意向</div>
|
||||||
|
|
||||||
<!-- 提示语 (按原型 top=217-243) -->
|
<!-- 提示语 -->
|
||||||
<div class="hint-list">
|
<div class="hint-list">
|
||||||
<p>*项目公示中点击支持意向后,显示在此</p>
|
<p>*项目公示中点击"表达支持意向"后,显示在此</p>
|
||||||
<p>*支持意向不需要注册,但是如果已经注册账号,则显示账号状态</p>
|
<p>*支持意向不需要注册;已注册账号时,自动回填用户状态</p>
|
||||||
<p>*根据手机号与系统账号进行匹配</p>
|
<p>*根据手机号与系统账号进行匹配</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ========== 筛选区 (与 People.vue 风格一致) ========== -->
|
<!-- ========== 筛选区 ========== -->
|
||||||
<el-form inline :model="q" class="filter-form">
|
<el-form inline :model="q" class="filter-form">
|
||||||
<el-form-item label="项目编号"><el-input v-model="q.projectNo" placeholder="如 ZH-2026-658" clearable /></el-form-item>
|
<el-form-item label="项目编号"><el-input v-model="q.projectNo" placeholder="如 ZH-2026-658" clearable /></el-form-item>
|
||||||
<el-form-item label="意向项目名称"><el-input v-model="q.projectName" placeholder="输入意向项目名称" clearable /></el-form-item>
|
<el-form-item label="意向项目名称"><el-input v-model="q.projectName" placeholder="输入意向项目名称" clearable /></el-form-item>
|
||||||
<el-form-item label="姓名"><el-input v-model="q.name" placeholder="输入姓名" clearable /></el-form-item>
|
<el-form-item label="姓名"><el-input v-model="q.name" placeholder="输入姓名" clearable /></el-form-item>
|
||||||
<el-form-item label="工作单位"><el-input v-model="q.workUnit" placeholder="输入工作单位" clearable /></el-form-item>
|
<el-form-item label="工作单位"><el-input v-model="q.workUnit" placeholder="输入工作单位" clearable /></el-form-item>
|
||||||
|
<el-form-item label="手机号"><el-input v-model="q.phone" placeholder="输入手机号" clearable /></el-form-item>
|
||||||
|
<el-form-item label="审核状态">
|
||||||
|
<el-select v-model="q.intentStatus" clearable style="width: 130px">
|
||||||
|
<el-option label="待审核" value="待审核" />
|
||||||
|
<el-option label="已通过" value="已通过" />
|
||||||
|
<el-option label="已拒绝" value="已拒绝" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="load">查找</el-button>
|
<el-button type="primary" @click="load">查找</el-button>
|
||||||
<el-button @click="reset">重置</el-button>
|
<el-button @click="reset">重置</el-button>
|
||||||
|
<el-button type="success" @click="exportCsv">导出CSV</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- ========== 表格 (与 People.vue 风格一致, 无 page-card 包裹) ========== -->
|
<!-- ========== 表格 ========== -->
|
||||||
<el-table :data="rows" v-loading="loading" stripe border>
|
<el-table :data="rows" v-loading="loading" stripe border @selection-change="onSelChange">
|
||||||
|
<el-table-column type="selection" width="46" />
|
||||||
<el-table-column type="index" label="#" width="50" />
|
<el-table-column type="index" label="#" width="50" />
|
||||||
<el-table-column prop="projectNo" label="支持意向项目编号" width="140" align="center" />
|
<el-table-column prop="projectNo" label="项目编号" width="140" align="center" />
|
||||||
<el-table-column prop="projectName" label="支持意向项目名称" min-width="200" show-overflow-tooltip />
|
<el-table-column prop="projectName" label="意向项目名称" min-width="200" show-overflow-tooltip />
|
||||||
<el-table-column prop="name" label="姓名" width="80" align="center" />
|
<el-table-column prop="name" label="姓名" width="80" align="center" />
|
||||||
<el-table-column prop="workUnit" label="工作单位名称" min-width="180" show-overflow-tooltip />
|
<el-table-column prop="workUnit" label="工作单位" min-width="180" show-overflow-tooltip />
|
||||||
<el-table-column prop="department" label="部门" width="120" align="center" />
|
<el-table-column prop="department" label="部门" width="120" align="center" />
|
||||||
<el-table-column prop="position" label="职务" width="120" align="center" />
|
<el-table-column prop="position" label="职务" width="120" align="center" />
|
||||||
<el-table-column prop="phone" label="手机号" width="130" align="center" />
|
<el-table-column prop="phone" label="手机号" width="130" align="center" />
|
||||||
<el-table-column label="账号状态" width="100" align="center">
|
<el-table-column label="账号状态" width="100" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.accountStatus==='存在' ? 'success' : 'warning'">{{ row.accountStatus || '不存在' }}</el-tag>
|
<el-tag :type="row.userId ? 'success' : 'warning'">{{ row.userId ? '存在' : '不存在' }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="审核状态" width="100" align="center">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="statusTagType(row.intentStatus)">{{ row.intentStatus || '待审核' }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="createTime" label="创建时间" width="170" align="center" />
|
||||||
|
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button v-if="row.intentStatus !== '已通过'" type="primary" link size="small" @click="changeStatus(row, '已通过')">通过</el-button>
|
||||||
|
<el-button v-if="row.intentStatus !== '已拒绝'" type="danger" link size="small" @click="changeStatus(row, '已拒绝')">拒绝</el-button>
|
||||||
|
<el-button v-if="row.intentStatus !== '待审核'" type="warning" link size="small" @click="changeStatus(row, '待审核')">重置</el-button>
|
||||||
|
<el-button type="danger" link size="small" @click="removeOne(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="pager">
|
<div class="pager">
|
||||||
|
<div class="pager-left">
|
||||||
|
<el-button type="danger" :disabled="!selected.length" @click="removeBatch">批量删除 ({{ selected.length }})</el-button>
|
||||||
|
</div>
|
||||||
<el-pagination v-model:current-page="page.pageNum" v-model:page-size="page.pageSize" :total="page.total" :page-sizes="[10,20,50]" layout="total, sizes, prev, pager, next, jumper" @current-change="load" @size-change="load" />
|
<el-pagination v-model:current-page="page.pageNum" v-model:page-size="page.pageSize" :total="page.total" :page-sizes="[10,20,50]" layout="total, sizes, prev, pager, next, jumper" @current-change="load" @size-change="load" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,34 +72,113 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { bizList } from '@/api/public'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import {
|
||||||
|
listPublicitySupportIntent,
|
||||||
|
updatePublicitySupportIntent,
|
||||||
|
deletePublicitySupportIntent
|
||||||
|
} from '@/api/public'
|
||||||
|
|
||||||
const q = ref({ projectNo: '', projectName: '', name: '', workUnit: '' })
|
const q = ref({ projectNo: '', projectName: '', name: '', workUnit: '', phone: '', intentStatus: '' })
|
||||||
const rows = ref([])
|
const rows = ref([])
|
||||||
|
const selected = ref([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
|
const page = reactive({ pageNum: 1, pageSize: 10, total: 0 })
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const { data } = await bizList('supportIntent', { ...q.value, pageNum: page.pageNum, pageSize: page.pageSize })
|
const { data } = await listPublicitySupportIntent({ ...q.value, pageNum: page.pageNum, pageSize: page.pageSize })
|
||||||
rows.value = data?.rows || []; page.total = data?.total || 0
|
rows.value = data?.rows || []
|
||||||
} catch { rows.value = []; page.total = 0 }
|
page.total = data?.total || 0
|
||||||
finally { loading.value = false }
|
} catch {
|
||||||
|
rows.value = []; page.total = 0
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
q.value = { projectNo: '', projectName: '', name: '', workUnit: '', phone: '', intentStatus: '' }
|
||||||
|
page.pageNum = 1
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelChange(arr) { selected.value = arr }
|
||||||
|
|
||||||
|
function statusTagType(s) {
|
||||||
|
if (s === '已通过') return 'success'
|
||||||
|
if (s === '已拒绝') return 'danger'
|
||||||
|
return 'warning'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeStatus(row, status) {
|
||||||
|
try {
|
||||||
|
await updatePublicitySupportIntent({ intentId: row.intentId, intentStatus: status }, { __silentError: true })
|
||||||
|
ElMessage.success(`已${status === '已通过' ? '通过' : status === '已拒绝' ? '拒绝' : '重置'}`)
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.msg || '状态变更失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeOne(row) {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`确认删除 ${row.name} 的支持意向?`, '提示', { type: 'warning' })
|
||||||
|
} catch { return }
|
||||||
|
try {
|
||||||
|
await deletePublicitySupportIntent([row.intentId])
|
||||||
|
ElMessage.success('已删除')
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.msg || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeBatch() {
|
||||||
|
if (!selected.value.length) return
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`确认删除 ${selected.value.length} 条支持意向?`, '提示', { type: 'warning' })
|
||||||
|
} catch { return }
|
||||||
|
try {
|
||||||
|
const ids = selected.value.map(r => r.intentId)
|
||||||
|
await deletePublicitySupportIntent(ids)
|
||||||
|
ElMessage.success('已删除')
|
||||||
|
load()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.msg || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 客户端导出 CSV (UTF-8 BOM 避免 Excel 乱码)
|
||||||
|
function exportCsv() {
|
||||||
|
if (!rows.value.length) return ElMessage.warning('当前列表无数据')
|
||||||
|
const headers = ['项目编号', '项目名称', '姓名', '工作单位', '部门', '职务', '手机号', '账号状态', '审核状态', '创建时间']
|
||||||
|
const csvRows = rows.value.map(r => [
|
||||||
|
r.projectNo, r.projectName, r.name, r.workUnit, r.department, r.position,
|
||||||
|
r.phone, r.userId ? '存在' : '不存在', r.intentStatus || '待审核', r.createTime
|
||||||
|
].map(v => `"` + String(v ?? '').replace(/"/g, '""') + `"`).join(','))
|
||||||
|
const csv = '' + [headers.join(','), ...csvRows].join('\r\n')
|
||||||
|
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' })
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const a = document.createElement('a')
|
||||||
|
a.href = url
|
||||||
|
a.download = `支持意向_${new Date().toISOString().slice(0, 10)}.csv`
|
||||||
|
document.body.appendChild(a); a.click(); document.body.removeChild(a)
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
ElMessage.success(`已导出 ${rows.value.length} 条`)
|
||||||
}
|
}
|
||||||
function reset() { q.value = { projectNo:'', projectName:'', name:'', workUnit:'' }; page.pageNum = 1; load() }
|
|
||||||
|
|
||||||
onMounted(load)
|
onMounted(load)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 整页面板 (与 People.vue 风格一致) */
|
|
||||||
.manager-support-intent { padding: 16px; }
|
.manager-support-intent { padding: 16px; }
|
||||||
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
|
.breadcrumb { font-size: 13px; color: #8c8c8c; margin-bottom: 12px; }
|
||||||
.filter-form { margin-bottom: 12px; }
|
.filter-form { margin-bottom: 12px; }
|
||||||
.pager { display: flex; justify-content: flex-end; margin-top: 12px; }
|
.pager { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; }
|
||||||
|
.pager-left { display: flex; gap: 8px; }
|
||||||
|
|
||||||
/* 红字提示 (与 People.vue 一致) */
|
|
||||||
.hint-list {
|
.hint-list {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
|
|||||||
@@ -98,6 +98,12 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span>{{ signed ? '已报名' : (signing ? '报名中…' : '立即报名') }}</span>
|
<span>{{ signed ? '已报名' : (signing ? '报名中…' : '立即报名') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button class="action-btn primary" :disabled="supportSubmitting || supportSubmitted" @click="onSupportIntent">
|
||||||
|
<span>{{ supportSubmitted ? '已支持' : (supportSubmitting ? '提交中…' : '表达支持意向') }}</span>
|
||||||
|
</button>
|
||||||
|
<button class="action-btn primary" :disabled="executionSubmitting || executionSubmitted" @click="onExecutionIntent">
|
||||||
|
<span>{{ executionSubmitted ? '已表达意向' : (executionSubmitting ? '提交中…' : '表达执行意向') }}</span>
|
||||||
|
</button>
|
||||||
<button class="action-btn primary share-btn" @click="showQr = true">
|
<button class="action-btn primary share-btn" @click="showQr = true">
|
||||||
<svg class="btn-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14">
|
<svg class="btn-icon" viewBox="0 0 24 24" fill="currentColor" width="14" height="14">
|
||||||
<path d="M3 11h8V3H3v8zm2-6h4v4H5V5zm8-2v8h8V3h-8zm6 6h-4V5h4v4zM3 21h8v-8H3v8zm2-6h4v4H5v-4z"/>
|
<path d="M3 11h8V3H3v8zm2-6h4v4H5V5zm8-2v8h8V3h-8zm6 6h-4V5h4v4zM3 21h8v-8H3v8zm2-6h4v4H5v-4z"/>
|
||||||
@@ -177,15 +183,51 @@
|
|||||||
<el-button type="primary" :disabled="!qrUrl" @click="onDownloadQr">下载二维码</el-button>
|
<el-button type="primary" :disabled="!qrUrl" @click="onDownloadQr">下载二维码</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- ========== 匿名意向收集 dialog (未登录时弹出, 已登录时直接提交) ========== -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="guestDialog.open"
|
||||||
|
:title="guestDialog.title"
|
||||||
|
width="480px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<el-form :model="guestDialog.form" label-width="100px">
|
||||||
|
<el-form-item label="姓名 *" required>
|
||||||
|
<el-input v-model="guestDialog.form.name" placeholder="请输入姓名" maxlength="50" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号 *" required>
|
||||||
|
<el-input v-model="guestDialog.form.phone" placeholder="请输入手机号" maxlength="11" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="工作单位 *" required>
|
||||||
|
<el-input v-model="guestDialog.form.workUnit" placeholder="请输入工作单位" maxlength="200" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="部门">
|
||||||
|
<el-input v-model="guestDialog.form.department" placeholder="选填" maxlength="100" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="职务">
|
||||||
|
<el-input v-model="guestDialog.form.position" placeholder="选填" maxlength="100" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="guestDialog.open = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="guestDialog.submitting" @click="onGuestDialogConfirm">提交意向</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
|
import { ref, computed, watch, reactive, onMounted, onBeforeUnmount } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { useUserStore } from '@/store/user'
|
import { useUserStore } from '@/store/user'
|
||||||
import { logout as logoutApi } from '@/api/auth'
|
import { logout as logoutApi } from '@/api/auth'
|
||||||
|
import {
|
||||||
|
submitPublicitySupportIntent,
|
||||||
|
submitPublicityExecutionIntent,
|
||||||
|
hasPublicityIntent
|
||||||
|
} from '@/api/public'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import QRCode from 'qrcode'
|
import QRCode from 'qrcode'
|
||||||
|
|
||||||
@@ -318,6 +360,7 @@ async function load() {
|
|||||||
if (firstKey) activeTab.value = firstKey
|
if (firstKey) activeTab.value = firstKey
|
||||||
// 项目加载完, 同步查"是否已报名"
|
// 项目加载完, 同步查"是否已报名"
|
||||||
checkSigned()
|
checkSigned()
|
||||||
|
refreshIntentStatus()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[publicity-detail] load failed', e)
|
console.error('[publicity-detail] load failed', e)
|
||||||
ann.value = null
|
ann.value = null
|
||||||
@@ -384,6 +427,119 @@ async function onSignup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============ 公示页-支持/执行意向 (匿名 + 已登录均可) ============
|
||||||
|
const supportSubmitting = ref(false)
|
||||||
|
const supportSubmitted = ref(false)
|
||||||
|
const executionSubmitting = ref(false)
|
||||||
|
const executionSubmitted = ref(false)
|
||||||
|
|
||||||
|
// 持久化"已提交"标记 - 已登录按 sys_user.phonenumber, 未登录无身份只能本次会话判定
|
||||||
|
async function checkIntentSubmitted(type) {
|
||||||
|
const proj = ann.value || {}
|
||||||
|
const projectId = proj.projectId || proj.id
|
||||||
|
if (!projectId) return false
|
||||||
|
// 已登录: 用登录用户的手机号去查
|
||||||
|
const phone = userStore.user?.phonenumber || userStore.user?.phoneNumber
|
||||||
|
if (!phone) return false
|
||||||
|
try {
|
||||||
|
const res = await hasPublicityIntent(projectId, phone, type)
|
||||||
|
return res?.data === true
|
||||||
|
} catch (e) { return false }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshIntentStatus() {
|
||||||
|
supportSubmitted.value = await checkIntentSubmitted('support')
|
||||||
|
executionSubmitted.value = await checkIntentSubmitted('execution')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匿名 dialog (未登录时弹, 已登录直接提交)
|
||||||
|
const guestDialog = reactive({
|
||||||
|
open: false,
|
||||||
|
title: '',
|
||||||
|
type: '', // 'support' | 'execution'
|
||||||
|
submitting: false,
|
||||||
|
form: { name: '', phone: '', workUnit: '', department: '', position: '' }
|
||||||
|
})
|
||||||
|
|
||||||
|
function resetGuestForm() {
|
||||||
|
guestDialog.form = { name: '', phone: '', workUnit: '', department: '', position: '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSupportIntent() {
|
||||||
|
if (supportSubmitting.value || supportSubmitted.value) return
|
||||||
|
if (loggedIn.value) {
|
||||||
|
doSubmitIntent('support')
|
||||||
|
} else {
|
||||||
|
resetGuestForm()
|
||||||
|
guestDialog.type = 'support'
|
||||||
|
guestDialog.title = '表达支持意向'
|
||||||
|
guestDialog.open = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onExecutionIntent() {
|
||||||
|
if (executionSubmitting.value || executionSubmitted.value) return
|
||||||
|
if (loggedIn.value) {
|
||||||
|
doSubmitIntent('execution')
|
||||||
|
} else {
|
||||||
|
resetGuestForm()
|
||||||
|
guestDialog.type = 'execution'
|
||||||
|
guestDialog.title = '表达执行意向'
|
||||||
|
guestDialog.open = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onGuestDialogConfirm() {
|
||||||
|
const f = guestDialog.form
|
||||||
|
if (!f.name?.trim()) return ElMessage.warning('请输入姓名')
|
||||||
|
if (!f.phone?.trim()) return ElMessage.warning('请输入手机号')
|
||||||
|
if (!f.workUnit?.trim()) return ElMessage.warning('请输入工作单位名称')
|
||||||
|
guestDialog.submitting = true
|
||||||
|
try {
|
||||||
|
await doSubmitIntent(guestDialog.type, { name: f.name, phone: f.phone, workUnit: f.workUnit, department: f.department, position: f.position })
|
||||||
|
guestDialog.open = false
|
||||||
|
} catch { /* toast 由 doSubmitIntent 处理 */ }
|
||||||
|
finally { guestDialog.submitting = false }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实际提交: 已登录不带 5 字段 (后端从 sys_user 取 user_id, 但姓名/手机号/单位仍需 dialog 收集 — 故未登录分支专门处理;
|
||||||
|
// 已登录分支: 仍然弹 dialog 让用户填 5 字段, 仅 user_id 自动回填, 不复用登录信息是因为匿名流程设计的字段是访客视角的"姓名/手机号/单位/部门/职务",
|
||||||
|
// 与登录专家视角的"姓名/手机号/工作单位/科室/职称" 不完全一致; 但支持/执行意向两表字段一致, 所以走 dialog)
|
||||||
|
async function doSubmitIntent(type, fields) {
|
||||||
|
const proj = ann.value || {}
|
||||||
|
const projectId = proj.projectId || proj.id
|
||||||
|
if (!projectId) return ElMessage.warning('项目ID缺失,无法提交')
|
||||||
|
// fields 可能为空 (已登录快速通道) → 触发 dialog
|
||||||
|
if (!fields) {
|
||||||
|
resetGuestForm()
|
||||||
|
guestDialog.type = type
|
||||||
|
guestDialog.title = type === 'support' ? '表达支持意向' : '表达执行意向'
|
||||||
|
guestDialog.open = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const setter = type === 'support' ? s => { supportSubmitting.value = s } : s => { executionSubmitting.value = s }
|
||||||
|
const markDone = type === 'support' ? () => { supportSubmitted.value = true } : () => { executionSubmitted.value = true }
|
||||||
|
setter(true)
|
||||||
|
try {
|
||||||
|
const payload = { projectId, ...fields }
|
||||||
|
const fn = type === 'support' ? submitPublicitySupportIntent : submitPublicityExecutionIntent
|
||||||
|
const res = await fn(payload)
|
||||||
|
if (res?.code === 200) {
|
||||||
|
markDone()
|
||||||
|
ElMessage.success(type === 'support' ? '已记录您的支持意向' : '已记录您的执行意向')
|
||||||
|
} else {
|
||||||
|
const msg = res?.msg || '提交失败,请稍后再试'
|
||||||
|
if (typeof msg === 'string' && msg.includes('已提交')) markDone()
|
||||||
|
ElMessage.error(msg)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[publicity-detail] submit intent failed', e)
|
||||||
|
ElMessage.error('提交失败,请稍后再试')
|
||||||
|
} finally {
|
||||||
|
setter(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onKeydown(e) { if (e.key === 'Escape') showQr.value = false }
|
function onKeydown(e) { if (e.key === 'Escape') showQr.value = false }
|
||||||
function handleScroll() { isScrolled.value = window.scrollY > 10 }
|
function handleScroll() { isScrolled.value = window.scrollY > 10 }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user