提交代码
This commit is contained in:
commit
6d2a23942a
20 files changed
+4194
-324
No files matched your search
+13
@@ -347,4 +347,17 @@ public class JcbtWorkStudyApplicationController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生已申请岗位列表
|
||||
*/
|
||||
@Operation(summary = "获取学生已申请岗位列表")
|
||||
@GetMapping("/student/applicationStatus")
|
||||
@SaCheckPermission("jcbt:workStudyApplication:query")
|
||||
public R<List<Map<String, Object>>> getStudentApplicationStatus() {
|
||||
|
||||
List<Map<String, Object>> statusList = workStudyApplicationService.getStudentApplicationStatus();
|
||||
return R.ok(statusList);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+57
-3
@@ -416,10 +416,64 @@ public class JcbtWorkStudyPositionController extends BaseController {
|
||||
|
||||
/**
|
||||
* 获取当前用户所在学院ID
|
||||
* TODO: 实现获取当前用户学院ID的逻辑
|
||||
* 通过查询学生信息或用户部门信息获取
|
||||
*/
|
||||
private Long getCurrentUserCollegeId() {
|
||||
// 临时返回固定值,实际应该从用户信息中获取
|
||||
return 1L;
|
||||
try {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null) {
|
||||
log.warn("用户未登录");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 首先尝试通过学生信息获取学院ID
|
||||
try {
|
||||
XgStudentMsgVo studentInfo = xgStudentMsgService.queryByUserId(userId);
|
||||
if (studentInfo != null && studentInfo.getCollegeId() != null) {
|
||||
log.debug("通过学生信息获取学院ID: {}", studentInfo.getCollegeId());
|
||||
return Long.parseLong(studentInfo.getCollegeId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("通过学生信息获取学院ID失败,可能用户不是学生: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 如果不是学生用户,通过用户部门信息获取学院ID
|
||||
try {
|
||||
Long deptId = LoginHelper.getDeptId();
|
||||
if (deptId != null) {
|
||||
log.debug("通过部门信息获取学院ID: {}", deptId);
|
||||
return deptId;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("通过部门信息获取学院ID失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 尝试通过部门类别获取学院信息
|
||||
try {
|
||||
String deptCategory = LoginHelper.getDeptCategory();
|
||||
String deptName = LoginHelper.getDeptName();
|
||||
log.debug("用户部门信息 - 部门名称: {}, 部门类别: {}", deptName, deptCategory);
|
||||
|
||||
// 如果部门类别是学院类型,则使用部门ID作为学院ID
|
||||
if ("college".equals(deptCategory) || "学院".equals(deptCategory)) {
|
||||
Long deptId = LoginHelper.getDeptId();
|
||||
if (deptId != null) {
|
||||
log.info("根据部门类别确认为学院用户,学院ID: {}", deptId);
|
||||
return deptId;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("通过部门类别获取学院ID失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
log.warn("无法获取用户 {} 的学院信息,用户ID: {}, 部门ID: {}, 部门名称: {}",
|
||||
userId, userId, LoginHelper.getDeptId(), LoginHelper.getDeptName());
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前用户学院ID失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -5,6 +5,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.jcbt.domain.JcbtWorkStudyApplication;
|
||||
import org.dromara.jcbt.domain.vo.JcbtWorkStudyApplicationVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -24,4 +25,6 @@ public interface JcbtWorkStudyApplicationMapper extends BaseMapperPlus<JcbtWorkS
|
||||
*/
|
||||
Map<String, Object> selectApplicationStatus(@Param("positionId") Long positionId, @Param("userId") Long userId);
|
||||
|
||||
List<Map<String, Object>> selectApplicationStatusByStudentId(@Param("studentId") Long studentId);
|
||||
|
||||
}
|
||||
+6
@@ -164,4 +164,10 @@ public interface IJcbtWorkStudyApplicationService {
|
||||
*/
|
||||
Map<String, Object> getPositionApplicationStatistics(Long positionId);
|
||||
|
||||
/**
|
||||
* 获取学生已申请岗位列表
|
||||
*
|
||||
* @return 学生已申请岗位状态列表 (包含岗位ID和申请状态)
|
||||
*/
|
||||
List<Map<String, Object>> getStudentApplicationStatus();
|
||||
}
|
||||
+70
-7
@@ -28,6 +28,9 @@ import org.dromara.xg.domain.vo.XgStudentMsgVo;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -338,25 +341,35 @@ public class JcbtWorkStudyApplicationServiceImpl implements IJcbtWorkStudyApplic
|
||||
|
||||
// 更新总状态 - 关键修改:确保状态正确更新
|
||||
String oldStatus = application.getStatus();
|
||||
if ("APPROVED".equals(reviewBo.getReviewResult())) {
|
||||
|
||||
// 标准化审核结果参数,兼容前端传递的小写值
|
||||
String reviewResult = reviewBo.getReviewResult();
|
||||
if (reviewResult != null) {
|
||||
reviewResult = reviewResult.toUpperCase();
|
||||
}
|
||||
|
||||
if ("APPROVED".equals(reviewResult)) {
|
||||
application.setStatus(WorkStudyApplicationStatusEnum.COLLEGE_APPROVED.getCode());
|
||||
log.info("🔍 [学院审核] 审核通过,状态更新: {} -> {}", oldStatus, WorkStudyApplicationStatusEnum.COLLEGE_APPROVED.getCode());
|
||||
} else if ("REJECTED".equals(reviewBo.getReviewResult())) {
|
||||
} else if ("REJECTED".equals(reviewResult)) {
|
||||
application.setStatus(WorkStudyApplicationStatusEnum.COLLEGE_REJECTED.getCode());
|
||||
log.info("🔍 [学院审核] 审核拒绝,状态更新: {} -> {}", oldStatus, WorkStudyApplicationStatusEnum.COLLEGE_REJECTED.getCode());
|
||||
} else {
|
||||
throw new ServiceException("审核结果参数错误,只支持approved或rejected");
|
||||
}
|
||||
|
||||
// 使用updateById确保更新
|
||||
boolean result = baseMapper.updateById(application) > 0;
|
||||
log.info("🔍 [学院审核] 数据库更新结果: {}", result ? "成功" : "失败");
|
||||
|
||||
if (result) {
|
||||
if (result) {
|
||||
// 验证更新后的状态
|
||||
JcbtWorkStudyApplication updatedApplication = baseMapper.selectById(reviewBo.getApplicationId());
|
||||
log.info("🔍 [学院审核] 更新后验证状态: {}, 审核状态: {}", updatedApplication.getStatus(), updatedApplication.getCollegeReviewStatus());
|
||||
|
||||
// 确保状态更新成功
|
||||
if ("APPROVED".equals(reviewBo.getReviewResult()) && !WorkStudyApplicationStatusEnum.COLLEGE_APPROVED.getCode().equals(updatedApplication.getStatus())) {
|
||||
String normalizedResult = reviewBo.getReviewResult() != null ? reviewBo.getReviewResult().toUpperCase() : "";
|
||||
if ("APPROVED".equals(normalizedResult) && !WorkStudyApplicationStatusEnum.COLLEGE_APPROVED.getCode().equals(updatedApplication.getStatus())) {
|
||||
log.error("🔍 [学院审核] 状态更新失败!期望: {}, 实际: {}", WorkStudyApplicationStatusEnum.COLLEGE_APPROVED.getCode(), updatedApplication.getStatus());
|
||||
throw new ServiceException("状态更新失败,请重试");
|
||||
}
|
||||
@@ -388,8 +401,13 @@ public class JcbtWorkStudyApplicationServiceImpl implements IJcbtWorkStudyApplic
|
||||
application.setFinalReviewerName(currentUserName);
|
||||
application.setFinalReviewComment(reviewBo.getReviewComment());
|
||||
|
||||
// 更新总状态
|
||||
if ("APPROVED".equals(reviewBo.getReviewResult())) {
|
||||
// 更新总状态 - 标准化审核结果参数,兼容前端传递的小写值
|
||||
String reviewResult = reviewBo.getReviewResult();
|
||||
if (reviewResult != null) {
|
||||
reviewResult = reviewResult.toUpperCase();
|
||||
}
|
||||
|
||||
if ("APPROVED".equals(reviewResult)) {
|
||||
application.setStatus(WorkStudyApplicationStatusEnum.FINAL_APPROVED.getCode());
|
||||
|
||||
// 更新岗位当前申请通过人数
|
||||
@@ -402,8 +420,10 @@ public class JcbtWorkStudyApplicationServiceImpl implements IJcbtWorkStudyApplic
|
||||
}
|
||||
positionMapper.updateById(position);
|
||||
}
|
||||
} else if ("REJECTED".equals(reviewBo.getReviewResult())) {
|
||||
} else if ("REJECTED".equals(reviewResult)) {
|
||||
application.setStatus(WorkStudyApplicationStatusEnum.FINAL_REJECTED.getCode());
|
||||
} else {
|
||||
throw new ServiceException("审核结果参数错误,只支持approved或rejected");
|
||||
}
|
||||
|
||||
return baseMapper.updateById(application) > 0;
|
||||
@@ -529,4 +549,47 @@ public class JcbtWorkStudyApplicationServiceImpl implements IJcbtWorkStudyApplic
|
||||
return statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生已申请岗位状态列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getStudentApplicationStatus() {
|
||||
Long studentId = LoginHelper.getUserId();
|
||||
List<Map<String, Object>> resultList = baseMapper.selectApplicationStatusByStudentId(studentId);
|
||||
|
||||
// 转换数据结构并进行状态值转换
|
||||
List<Map<String, Object>> statusList = new ArrayList<>();
|
||||
for (Map<String, Object> item : resultList) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("positionId", item.get("position_id"));
|
||||
result.put("status", convertStatusToFrontend((String) item.get("status")));
|
||||
statusList.add(result);
|
||||
}
|
||||
|
||||
return statusList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将后端状态转换为前端状态
|
||||
*/
|
||||
private String convertStatusToFrontend(String backendStatus) {
|
||||
if (backendStatus == null) {
|
||||
return "submitted";
|
||||
}
|
||||
switch (backendStatus) {
|
||||
case "SUBMITTED":
|
||||
return "submitted";
|
||||
case "COLLEGE_APPROVED":
|
||||
return "college_reviewing";
|
||||
case "FINAL_APPROVED":
|
||||
return "approved";
|
||||
case "COLLEGE_REJECTED":
|
||||
case "FINAL_REJECTED":
|
||||
return "rejected";
|
||||
case "CANCELLED":
|
||||
return "cancelled";
|
||||
default:
|
||||
return "submitted";
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -133,4 +133,10 @@
|
||||
AND deleted = 0
|
||||
</select>
|
||||
|
||||
<select id="selectApplicationStatusByStudentId" resultType="java.util.Map">
|
||||
SELECT position_id, status
|
||||
FROM jcbt_work_study_application
|
||||
WHERE student_id = #{studentId} AND deleted = 0
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,133 @@
|
||||
// 勤工俭学API接口
|
||||
import { request } from '@/common/request.js';
|
||||
|
||||
/**
|
||||
* 学生查看可申请的岗位列表
|
||||
* @param {Object} params 查询参数
|
||||
*/
|
||||
export const getAvailablePositions = (params = {}) => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyPosition/visibleList',
|
||||
method: 'GET',
|
||||
params: {
|
||||
...params,
|
||||
excludeApplied: true // 排除已申请的岗位
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取岗位详情及申请状态
|
||||
* @param {String|Number} positionId 岗位ID
|
||||
*/
|
||||
export const getPositionWithApplicationStatus = (positionId) => {
|
||||
return request({
|
||||
url: `/jcbt/workStudyPosition/${positionId}/withApplicationStatus`,
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看我的申请列表
|
||||
* @param {Object} params 查询参数
|
||||
*/
|
||||
export const getMyApplications = (params = {}) => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication/myList',
|
||||
method: 'GET',
|
||||
params: params
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增申请
|
||||
* @param {Object} data 申请数据
|
||||
*/
|
||||
export const addApplication = (data) => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication',
|
||||
method: 'POST',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 提交申请
|
||||
* @param {String|Number} applicationId 申请ID
|
||||
*/
|
||||
export const submitApplication = (applicationId) => {
|
||||
return request({
|
||||
url: `/jcbt/workStudyApplication/submit/${applicationId}`,
|
||||
method: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 撤销申请
|
||||
* @param {String|Number} applicationId 申请ID
|
||||
*/
|
||||
export const cancelApplication = (applicationId) => {
|
||||
return request({
|
||||
url: `/jcbt/workStudyApplication/cancel/${applicationId}`,
|
||||
method: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前学生信息
|
||||
*/
|
||||
export const getCurrentStudentInfo = () => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication/currentStudentInfo',
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取申请选项数据
|
||||
*/
|
||||
export const getApplicationOptions = () => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication/options',
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查重复申请
|
||||
* @param {String} studentNumber 学号
|
||||
* @param {Number} positionId 岗位ID
|
||||
*/
|
||||
export const checkDuplicateApplication = (studentNumber, positionId) => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication/checkDuplicate',
|
||||
method: 'GET',
|
||||
params: {
|
||||
studentNumber: studentNumber,
|
||||
positionId: positionId
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询申请详情
|
||||
* @param {String|Number} applicationId 申请ID
|
||||
*/
|
||||
export const getApplicationDetail = (applicationId) => {
|
||||
return request({
|
||||
url: `/jcbt/workStudyApplication/detail/${applicationId}`,
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改申请
|
||||
* @param {Object} data 申请数据
|
||||
*/
|
||||
export const updateApplication = (data) => {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
+304
-256
@@ -1,257 +1,305 @@
|
||||
{
|
||||
"easycom": {
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "杭州第一技师学院智慧校园",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/myDocument",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我发起的",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/allTaskWaiting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的待办",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/taskWaiting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的待办",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/taskFinish",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的已办",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/taskCopyList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "抄送我的",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsjcxx/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生个人信息",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsws/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生信息完善",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsws/stuMsgDialog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "信息完善",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsws/stuMsgDetailDialog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提交历史",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsqj/leave/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生请假",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsqj/leaveEdit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsqj/cancelLeaveEdit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生销假",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/wechat/js-sdk-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "微信JS-SDK测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/internship/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "实习打卡",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "班主任走访",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/add",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增走访",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "走访详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/edit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑走访",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/sswj/grsswj",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍违纪",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/sswj/sswjDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "违纪详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/wsjc/wsjc",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/wsjc/wsjcAdd",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增宿舍卫生检查",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/wsjc/wsjcDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/xssswsjc/xssswsjc",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/xssswsjc/xssswsjcDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/enrollment/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新生报名登记",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/wjjl/xswjjl",
|
||||
"style": {
|
||||
"navigationBarTitleText": "违纪记录(学生)",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/wjjl/revokeApplication",
|
||||
"style": {
|
||||
"navigationBarTitleText": "撤销申请",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/khsq/khsq",
|
||||
"style": {
|
||||
"navigationBarTitleText": "考核申请",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "智慧校园",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
}
|
||||
{
|
||||
"easycom": {
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "杭州第一技师学院智慧校园",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/myDocument",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我发起的",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/allTaskWaiting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的待办",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/taskWaiting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的待办",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/taskFinish",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的已办",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/task/taskCopyList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "抄送我的",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsjcxx/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生个人信息",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsws/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生信息完善",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsws/stuMsgDialog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "信息完善",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsws/stuMsgDetailDialog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提交历史",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsqj/leave/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生请假",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsqj/leaveEdit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "请假申请",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xg/xsjcxx/xsqj/cancelLeaveEdit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生销假",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/wechat/js-sdk-test",
|
||||
"style": {
|
||||
"navigationBarTitleText": "微信JS-SDK测试",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/internship/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "实习打卡",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "班主任走访",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/add",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增走访",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "走访详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/visit/edit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑走访",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/sswj/grsswj",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍违纪",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/sswj/sswjDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "违纪详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/wsjc/wsjc",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/wsjc/wsjcAdd",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增宿舍卫生检查",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/wsjc/wsjcDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/xssswsjc/xssswsjc",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xgss/xssswsjc/xssswsjcDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宿舍卫生检查详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/enrollment/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新生报名登记",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/wjjl/xswjjl",
|
||||
"style": {
|
||||
"navigationBarTitleText": "违纪记录(学生)",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/wjjl/revokeApplication",
|
||||
"style": {
|
||||
"navigationBarTitleText": "撤销申请",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/khsq/khsq",
|
||||
"style": {
|
||||
"navigationBarTitleText": "考核申请",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/khsq/form",
|
||||
"style": {
|
||||
"navigationBarTitleText": "考核申请表单",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/xskh/khsq/indicatorDataDialog",
|
||||
"style": {
|
||||
"navigationBarTitleText": "学生数据详情",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workStudy/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "勤工俭学",
|
||||
"navigationBarBackgroundColor": "#1890ff",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workStudy/detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "岗位详情",
|
||||
"navigationBarBackgroundColor": "#1890ff",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workStudy/apply",
|
||||
"style": {
|
||||
"navigationBarTitleText": "申请岗位",
|
||||
"navigationBarBackgroundColor": "#1890ff",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workStudy/applicationDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "申请详情",
|
||||
"navigationBarBackgroundColor": "#1890ff",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "智慧校园",
|
||||
"navigationBarBackgroundColor": "#0051d9",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
}
|
||||
}
|
||||
@@ -221,6 +221,20 @@
|
||||
</template>
|
||||
</ServiceItem>
|
||||
|
||||
<ServiceItem
|
||||
v-if="hasPermi(['student:workstudy:list'])"
|
||||
title="勤工俭学"
|
||||
@click="gotoWorkStudy"
|
||||
>
|
||||
<template #icon>
|
||||
<image
|
||||
src="/static/00127.png"
|
||||
mode="aspectFit"
|
||||
style="width: 24px; height: 24px"
|
||||
/>
|
||||
</template>
|
||||
</ServiceItem>
|
||||
|
||||
<ServiceItem
|
||||
v-if="hasPermi(['student:violation:list'])"
|
||||
title="违纪记录(学生)"
|
||||
@@ -674,6 +688,7 @@ export default {
|
||||
this.hasPermi(['student:dorm:violation:list']) ||
|
||||
this.hasPermi(['student:visit:list']) ||
|
||||
this.hasPermi(['student:dorm:hygiene:list']) ||
|
||||
this.hasPermi(['student:workstudy:list']) ||
|
||||
this.hasPermi(['student:violation:list']) ||
|
||||
this.hasPermi(['student:assessment:apply'])
|
||||
);
|
||||
@@ -910,6 +925,13 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到勤工俭学页面
|
||||
gotoWorkStudy() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workStudy/index',
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到学生违纪记录页面
|
||||
gotoStudentViolation() {
|
||||
uni.navigateTo({
|
||||
|
||||
@@ -0,0 +1,624 @@
|
||||
<template>
|
||||
<view class="detail-container">
|
||||
<!-- 申请状态卡片 -->
|
||||
<view class="status-card" v-if="applicationData">
|
||||
<view class="card-title">申请状态</view>
|
||||
<view class="status-info">
|
||||
<view class="main-status">
|
||||
<u-tag
|
||||
:text="getApplicationStatusText(applicationData.status)"
|
||||
:type="getApplicationStatusType(applicationData.status)"
|
||||
size="large"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
<view class="status-detail">
|
||||
<view class="status-item">
|
||||
<text class="status-label">申请时间:</text>
|
||||
<text class="status-value">{{ applicationData.createTime }}</text>
|
||||
</view>
|
||||
<view class="status-item" v-if="applicationData.updateTime !== applicationData.createTime">
|
||||
<text class="status-label">更新时间:</text>
|
||||
<text class="status-value">{{ applicationData.updateTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 岗位信息 -->
|
||||
<view class="info-card" v-if="applicationData">
|
||||
<view class="card-title">申请岗位</view>
|
||||
<view class="position-info">
|
||||
<view class="position-name">{{ applicationData.positionName }}</view>
|
||||
<view class="position-detail">
|
||||
<view class="detail-item">
|
||||
<u-icon name="list" size="28" color="#666" />
|
||||
<text>岗位类型:{{ applicationData.positionType }}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<u-icon name="map" size="28" color="#666" />
|
||||
<text>工作地点:{{ applicationData.workLocation }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<view class="info-card" v-if="applicationData">
|
||||
<view class="card-title">基本信息</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="info-label">学生姓名:</text>
|
||||
<text class="info-value">{{ applicationData.studentName }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">学号:</text>
|
||||
<text class="info-value">{{ applicationData.studentNumber }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">身份证号:</text>
|
||||
<text class="info-value">{{ formatIdCard(applicationData.idCard) }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">联系电话:</text>
|
||||
<text class="info-value contact-phone" @click="callPhone">{{ applicationData.contactPhone }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">学院:</text>
|
||||
<text class="info-value">{{ applicationData.collegeName }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">专业:</text>
|
||||
<text class="info-value">{{ applicationData.majorName }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">班级:</text>
|
||||
<text class="info-value">{{ applicationData.className }}</text>
|
||||
</view>
|
||||
<view class="info-item" v-if="applicationData.grade">
|
||||
<text class="info-label">年级:</text>
|
||||
<text class="info-value">{{ applicationData.grade }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请信息 -->
|
||||
<view class="info-card" v-if="applicationData">
|
||||
<view class="card-title">申请信息</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">
|
||||
<text class="info-label">家庭经济情况:</text>
|
||||
<text class="info-value">{{ applicationData.familyFinancialStatus }}</text>
|
||||
</view>
|
||||
<view class="info-item" v-if="applicationData.plannedWorkHours">
|
||||
<text class="info-label">计划工作时长:</text>
|
||||
<text class="info-value">{{ applicationData.plannedWorkHours }}小时/周</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请理由 -->
|
||||
<view class="content-card" v-if="applicationData && applicationData.applicationReason">
|
||||
<view class="card-title">申请理由</view>
|
||||
<view class="content-text">{{ applicationData.applicationReason }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 个人能力及经验 -->
|
||||
<view class="content-card" v-if="applicationData && applicationData.personalAbility">
|
||||
<view class="card-title">个人能力及经验</view>
|
||||
<view class="content-text">{{ applicationData.personalAbility }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 时间安排 -->
|
||||
<view class="content-card" v-if="applicationData && applicationData.timeArrangement">
|
||||
<view class="card-title">时间安排</view>
|
||||
<view class="content-text">{{ applicationData.timeArrangement }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 备注信息 -->
|
||||
<view class="content-card" v-if="applicationData && applicationData.remark">
|
||||
<view class="card-title">备注信息</view>
|
||||
<view class="content-text">{{ applicationData.remark }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 审核记录 -->
|
||||
<view class="review-card" v-if="hasReviewRecord">
|
||||
<view class="card-title">审核记录</view>
|
||||
|
||||
<!-- 学院审核 -->
|
||||
<view class="review-item" v-if="applicationData.collegeReviewStatus">
|
||||
<view class="review-header">
|
||||
<view class="review-title">学院审核</view>
|
||||
<u-tag
|
||||
:text="getReviewStatusText(applicationData.collegeReviewStatus)"
|
||||
:type="getReviewStatusType(applicationData.collegeReviewStatus)"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
<view class="review-info">
|
||||
<view class="review-detail" v-if="applicationData.collegeReviewTime">
|
||||
<text class="detail-label">审核时间:</text>
|
||||
<text class="detail-value">{{ applicationData.collegeReviewTime }}</text>
|
||||
</view>
|
||||
<view class="review-detail" v-if="applicationData.collegeReviewerName">
|
||||
<text class="detail-label">审核人员:</text>
|
||||
<text class="detail-value">{{ applicationData.collegeReviewerName }}</text>
|
||||
</view>
|
||||
<view class="review-comment" v-if="applicationData.collegeReviewComment">
|
||||
<text class="comment-label">审核意见:</text>
|
||||
<text class="comment-text">{{ applicationData.collegeReviewComment }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学生处审核 -->
|
||||
<view class="review-item" v-if="applicationData.finalReviewStatus">
|
||||
<view class="review-header">
|
||||
<view class="review-title">学生处审核</view>
|
||||
<u-tag
|
||||
:text="getReviewStatusText(applicationData.finalReviewStatus)"
|
||||
:type="getReviewStatusType(applicationData.finalReviewStatus)"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
<view class="review-info">
|
||||
<view class="review-detail" v-if="applicationData.finalReviewTime">
|
||||
<text class="detail-label">审核时间:</text>
|
||||
<text class="detail-value">{{ applicationData.finalReviewTime }}</text>
|
||||
</view>
|
||||
<view class="review-detail" v-if="applicationData.finalReviewerName">
|
||||
<text class="detail-label">审核人员:</text>
|
||||
<text class="detail-value">{{ applicationData.finalReviewerName }}</text>
|
||||
</view>
|
||||
<view class="review-comment" v-if="applicationData.finalReviewComment">
|
||||
<text class="comment-label">审核意见:</text>
|
||||
<text class="comment-text">{{ applicationData.finalReviewComment }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="bottom-actions" v-if="showActions">
|
||||
<u-button
|
||||
type="warning"
|
||||
size="large"
|
||||
@click="editApplication"
|
||||
v-if="canEdit"
|
||||
style="margin-right: 20rpx;"
|
||||
>
|
||||
编辑申请
|
||||
</u-button>
|
||||
<u-button
|
||||
type="error"
|
||||
size="large"
|
||||
@click="cancelApplication"
|
||||
v-if="canCancel"
|
||||
:loading="canceling"
|
||||
>
|
||||
撤销申请
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<u-loading-page :loading="loading" loading-text="加载中..." />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getApplicationDetail,
|
||||
cancelApplication
|
||||
} from '@/api/workStudy.js';
|
||||
|
||||
export default {
|
||||
name: 'ApplicationDetail',
|
||||
data() {
|
||||
return {
|
||||
applicationId: '',
|
||||
applicationData: null,
|
||||
loading: false,
|
||||
canceling: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
// 是否有审核记录
|
||||
hasReviewRecord() {
|
||||
return this.applicationData &&
|
||||
(this.applicationData.collegeReviewStatus || this.applicationData.finalReviewStatus);
|
||||
},
|
||||
|
||||
// 是否显示操作按钮
|
||||
showActions() {
|
||||
return this.canEdit || this.canCancel;
|
||||
},
|
||||
|
||||
// 是否可以编辑
|
||||
canEdit() {
|
||||
return this.applicationData &&
|
||||
['DRAFT', 'COLLEGE_REJECTED'].includes(this.applicationData.status);
|
||||
},
|
||||
|
||||
// 是否可以撤销
|
||||
canCancel() {
|
||||
return this.applicationData &&
|
||||
['DRAFT', 'SUBMITTED', 'COLLEGE_REVIEWING'].includes(this.applicationData.status);
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
if (options.id) {
|
||||
this.applicationId = options.id;
|
||||
this.loadApplicationDetail();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '申请ID不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 加载申请详情
|
||||
async loadApplicationDetail() {
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const response = await getApplicationDetail(this.applicationId);
|
||||
|
||||
if (response.code === 200) {
|
||||
this.applicationData = response.data;
|
||||
} else {
|
||||
throw new Error(response.msg || '获取申请详情失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载申请详情失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '加载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 编辑申请
|
||||
editApplication() {
|
||||
if (!this.applicationData) return;
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/workStudy/apply?positionId=${this.applicationData.positionId}&applicationId=${this.applicationData.id}&mode=edit`
|
||||
});
|
||||
},
|
||||
|
||||
// 撤销申请
|
||||
async cancelApplication() {
|
||||
try {
|
||||
const { confirm } = await uni.showModal({
|
||||
title: '确认撤销',
|
||||
content: '确定要撤销此申请吗?',
|
||||
showCancel: true
|
||||
});
|
||||
|
||||
if (!confirm) return; // 用户取消
|
||||
|
||||
this.canceling = true;
|
||||
const response = await cancelApplication(this.applicationData.id);
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: '撤销成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 重新加载数据
|
||||
setTimeout(() => {
|
||||
this.loadApplicationDetail();
|
||||
}, 1000);
|
||||
} else {
|
||||
throw new Error(response.msg || '撤销失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('撤销申请失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '撤销失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.canceling = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 拨打电话
|
||||
callPhone() {
|
||||
if (this.applicationData && this.applicationData.contactPhone) {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: this.applicationData.contactPhone,
|
||||
fail: (error) => {
|
||||
console.error('拨打电话失败:', error);
|
||||
uni.showToast({
|
||||
title: '拨打电话失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 格式化身份证号(中间位隐藏)
|
||||
formatIdCard(idCard) {
|
||||
if (!idCard || idCard.length < 10) return idCard;
|
||||
return idCard.substring(0, 6) + '********' + idCard.substring(idCard.length - 4);
|
||||
},
|
||||
|
||||
// 获取申请状态文字
|
||||
getApplicationStatusText(status) {
|
||||
const statusMap = {
|
||||
'DRAFT': '草稿',
|
||||
'SUBMITTED': '已提交',
|
||||
'COLLEGE_REVIEWING': '学院审核中',
|
||||
'COLLEGE_APPROVED': '学院审核通过',
|
||||
'COLLEGE_REJECTED': '学院审核未通过',
|
||||
'FINAL_REVIEWING': '学生处审核中',
|
||||
'FINAL_APPROVED': '审核通过',
|
||||
'FINAL_REJECTED': '审核未通过',
|
||||
'CANCELLED': '已撤销'
|
||||
};
|
||||
return statusMap[status] || '未知状态';
|
||||
},
|
||||
|
||||
// 获取申请状态类型
|
||||
getApplicationStatusType(status) {
|
||||
const typeMap = {
|
||||
'DRAFT': 'info',
|
||||
'SUBMITTED': 'warning',
|
||||
'COLLEGE_REVIEWING': 'warning',
|
||||
'COLLEGE_APPROVED': 'success',
|
||||
'COLLEGE_REJECTED': 'error',
|
||||
'FINAL_REVIEWING': 'warning',
|
||||
'FINAL_APPROVED': 'success',
|
||||
'FINAL_REJECTED': 'error',
|
||||
'CANCELLED': 'info'
|
||||
};
|
||||
return typeMap[status] || 'default';
|
||||
},
|
||||
|
||||
// 获取审核状态文字
|
||||
getReviewStatusText(status) {
|
||||
const statusMap = {
|
||||
'PENDING': '待审核',
|
||||
'APPROVED': '通过',
|
||||
'REJECTED': '未通过'
|
||||
};
|
||||
return statusMap[status] || '未知';
|
||||
},
|
||||
|
||||
// 获取审核状态类型
|
||||
getReviewStatusType(status) {
|
||||
const typeMap = {
|
||||
'PENDING': 'warning',
|
||||
'APPROVED': 'success',
|
||||
'REJECTED': 'error'
|
||||
};
|
||||
return typeMap[status] || 'default';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 120rpx; /* 为底部按钮留空间 */
|
||||
}
|
||||
|
||||
.status-card, .info-card, .content-card, .review-card {
|
||||
background-color: #fff;
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 24rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
/* 状态卡片 */
|
||||
.status-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.main-status {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.status-detail {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.status-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 岗位信息 */
|
||||
.position-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #1890ff;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.position-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.detail-item text {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
/* 信息列表 */
|
||||
.info-list {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
min-width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.contact-phone {
|
||||
color: #1890ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 内容卡片 */
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* 审核记录 */
|
||||
.review-item {
|
||||
margin-bottom: 30rpx;
|
||||
padding: 24rpx;
|
||||
background-color: #fafafa;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.review-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.review-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.review-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.review-info {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.review-detail {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.review-comment {
|
||||
margin-top: 16rpx;
|
||||
padding-top: 16rpx;
|
||||
border-top: 1rpx solid #e8e8e8;
|
||||
}
|
||||
|
||||
.comment-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.comment-text {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 底部操作 */
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
display: flex;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.bottom-actions .u-button {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,743 @@
|
||||
<template>
|
||||
<view class="apply-container">
|
||||
<!-- 岗位信息卡片 -->
|
||||
<view class="position-card" v-if="positionData">
|
||||
<view class="card-title">申请岗位</view>
|
||||
<view class="position-info">
|
||||
<view class="position-name">{{ positionData.positionName }}</view>
|
||||
<view class="position-detail">
|
||||
<text>工作时间:{{ positionData.workTime }}</text>
|
||||
<text>联系老师:{{ positionData.contactTeacher }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请表单 -->
|
||||
<view class="form-container">
|
||||
<u-form
|
||||
:model="formData"
|
||||
ref="form"
|
||||
label-width="140"
|
||||
label-position="left"
|
||||
>
|
||||
<!-- 基本信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">基本信息</view>
|
||||
|
||||
<u-form-item
|
||||
label="学生姓名"
|
||||
prop="studentName"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.studentName"
|
||||
placeholder="请输入学生姓名"
|
||||
:disabled="true"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="学号"
|
||||
prop="studentNumber"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.studentNumber"
|
||||
placeholder="请输入学号"
|
||||
:disabled="true"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="身份证号"
|
||||
prop="idCard"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.idCard"
|
||||
placeholder="请输入身份证号"
|
||||
maxlength="18"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="联系电话"
|
||||
prop="contactPhone"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.contactPhone"
|
||||
placeholder="请输入联系电话"
|
||||
maxlength="11"
|
||||
/>
|
||||
</u-form-item>
|
||||
</view>
|
||||
|
||||
<!-- 学籍信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">学籍信息</view>
|
||||
|
||||
<u-form-item
|
||||
label="学院名称"
|
||||
prop="collegeName"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.collegeName"
|
||||
placeholder="学院名称"
|
||||
:disabled="true"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="专业名称"
|
||||
prop="majorName"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.majorName"
|
||||
placeholder="专业名称"
|
||||
:disabled="true"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="班级名称"
|
||||
prop="className"
|
||||
:required="true"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.className"
|
||||
placeholder="班级名称"
|
||||
:disabled="true"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="年级"
|
||||
prop="grade"
|
||||
>
|
||||
<view @click="showGradePicker = true">
|
||||
<u-input
|
||||
v-model="gradeText"
|
||||
placeholder="请选择年级"
|
||||
readonly
|
||||
suffix-icon="arrow-down"
|
||||
/>
|
||||
</view>
|
||||
</u-form-item>
|
||||
</view>
|
||||
|
||||
<!-- 申请信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">申请信息</view>
|
||||
|
||||
<u-form-item
|
||||
label="家庭经济情况"
|
||||
prop="familyFinancialStatus"
|
||||
:required="true"
|
||||
>
|
||||
<view @click="showFinancialPicker = true">
|
||||
<u-input
|
||||
v-model="financialText"
|
||||
placeholder="请选择家庭经济情况"
|
||||
readonly
|
||||
suffix-icon="arrow-down"
|
||||
/>
|
||||
</view>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="计划工作时长"
|
||||
prop="plannedWorkHours"
|
||||
>
|
||||
<u-input
|
||||
v-model="formData.plannedWorkHours"
|
||||
placeholder="请输入计划工作时长(小时/周)"
|
||||
type="number"
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="申请理由"
|
||||
prop="applicationReason"
|
||||
:required="true"
|
||||
>
|
||||
<u-textarea
|
||||
v-model="formData.applicationReason"
|
||||
placeholder="请详细说明申请此岗位的理由"
|
||||
:maxlength="500"
|
||||
:show-word-limit="true"
|
||||
height="200"
|
||||
count
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="个人能力及经验"
|
||||
prop="personalAbility"
|
||||
:required="true"
|
||||
>
|
||||
<u-textarea
|
||||
v-model="formData.personalAbility"
|
||||
placeholder="请描述与岗位相关的个人能力和经验"
|
||||
:maxlength="500"
|
||||
:show-word-limit="true"
|
||||
height="200"
|
||||
count
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="时间安排"
|
||||
prop="timeArrangement"
|
||||
:required="true"
|
||||
>
|
||||
<u-textarea
|
||||
v-model="formData.timeArrangement"
|
||||
placeholder="请说明您的时间安排,确保能够胜任此岗位工作"
|
||||
:maxlength="300"
|
||||
:show-word-limit="true"
|
||||
height="150"
|
||||
count
|
||||
/>
|
||||
</u-form-item>
|
||||
|
||||
<u-form-item
|
||||
label="备注"
|
||||
prop="remark"
|
||||
>
|
||||
<u-textarea
|
||||
v-model="formData.remark"
|
||||
placeholder="其他需要说明的情况(选填)"
|
||||
:maxlength="200"
|
||||
:show-word-limit="true"
|
||||
height="120"
|
||||
count
|
||||
/>
|
||||
</u-form-item>
|
||||
</view>
|
||||
</u-form>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<u-button
|
||||
type="default"
|
||||
size="large"
|
||||
@click="saveDraft"
|
||||
:loading="saving"
|
||||
style="margin-right: 20rpx;"
|
||||
>
|
||||
保存草稿
|
||||
</u-button>
|
||||
<u-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="submitApplication"
|
||||
:loading="submitting"
|
||||
>
|
||||
提交申请
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 年级选择器 -->
|
||||
<u-picker
|
||||
:show="showGradePicker"
|
||||
:columns="gradeOptions"
|
||||
keyName="label"
|
||||
@confirm="onGradeConfirm"
|
||||
@cancel="showGradePicker = false"
|
||||
/>
|
||||
|
||||
<!-- 家庭经济情况选择器 -->
|
||||
<u-picker
|
||||
:show="showFinancialPicker"
|
||||
:columns="financialOptions"
|
||||
keyName="label"
|
||||
@confirm="onFinancialConfirm"
|
||||
@cancel="showFinancialPicker = false"
|
||||
/>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<u-loading-page :loading="loading" loading-text="加载中..." />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getPositionWithApplicationStatus,
|
||||
getCurrentStudentInfo,
|
||||
getApplicationOptions,
|
||||
addApplication,
|
||||
updateApplication,
|
||||
getApplicationDetail
|
||||
} from '@/api/workStudy.js';
|
||||
|
||||
export default {
|
||||
name: 'WorkStudyApply',
|
||||
data() {
|
||||
return {
|
||||
positionId: '',
|
||||
applicationId: '',
|
||||
mode: 'create', // create 或 edit
|
||||
positionData: null,
|
||||
studentInfo: null,
|
||||
|
||||
// 表单数据
|
||||
formData: {
|
||||
studentName: '',
|
||||
studentNumber: '',
|
||||
idCard: '',
|
||||
contactPhone: '',
|
||||
collegeName: '',
|
||||
majorName: '',
|
||||
className: '',
|
||||
grade: '',
|
||||
familyFinancialStatus: '',
|
||||
plannedWorkHours: '',
|
||||
applicationReason: '',
|
||||
personalAbility: '',
|
||||
timeArrangement: '',
|
||||
remark: ''
|
||||
},
|
||||
|
||||
// 选择器显示状态
|
||||
showGradePicker: false,
|
||||
showFinancialPicker: false,
|
||||
|
||||
// 选择器文本
|
||||
gradeText: '',
|
||||
financialText: '',
|
||||
|
||||
// 选择器选项
|
||||
gradeOptions: [[]],
|
||||
financialOptions: [[]],
|
||||
|
||||
// 加载状态
|
||||
loading: false,
|
||||
saving: false,
|
||||
submitting: false
|
||||
};
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
if (options.positionId) {
|
||||
this.positionId = options.positionId;
|
||||
this.applicationId = options.applicationId || '';
|
||||
this.mode = options.mode || 'create';
|
||||
|
||||
this.initData();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '岗位ID不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化数据
|
||||
async initData() {
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
// 并行加载数据
|
||||
const promises = [
|
||||
this.loadPositionData(),
|
||||
this.loadStudentInfo(),
|
||||
this.loadApplicationOptions()
|
||||
];
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
// 如果是编辑模式,加载申请详情
|
||||
if (this.mode === 'edit' && this.applicationId) {
|
||||
await this.loadApplicationDetail();
|
||||
}
|
||||
|
||||
// 填充学生基本信息
|
||||
this.fillStudentInfo();
|
||||
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error);
|
||||
uni.showToast({
|
||||
title: '加载数据失败',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载岗位数据
|
||||
async loadPositionData() {
|
||||
const response = await getPositionWithApplicationStatus(this.positionId);
|
||||
if (response.code === 200) {
|
||||
this.positionData = response.data.position;
|
||||
} else {
|
||||
throw new Error(response.msg || '获取岗位信息失败');
|
||||
}
|
||||
},
|
||||
|
||||
// 加载学生信息
|
||||
async loadStudentInfo() {
|
||||
const response = await getCurrentStudentInfo();
|
||||
if (response.code === 200) {
|
||||
this.studentInfo = response.data;
|
||||
} else {
|
||||
throw new Error(response.msg || '获取学生信息失败');
|
||||
}
|
||||
},
|
||||
|
||||
// 加载申请选项
|
||||
async loadApplicationOptions() {
|
||||
const response = await getApplicationOptions();
|
||||
if (response.code === 200) {
|
||||
const options = response.data;
|
||||
|
||||
// 设置年级选项
|
||||
this.gradeOptions = [options.gradeOptions || []];
|
||||
|
||||
// 设置家庭经济情况选项
|
||||
this.financialOptions = [options.familyFinancialStatusOptions || []];
|
||||
}
|
||||
},
|
||||
|
||||
// 加载申请详情(编辑模式)
|
||||
async loadApplicationDetail() {
|
||||
const response = await getApplicationDetail(this.applicationId);
|
||||
if (response.code === 200) {
|
||||
const data = response.data;
|
||||
|
||||
// 填充表单数据
|
||||
Object.keys(this.formData).forEach(key => {
|
||||
if (data[key] !== undefined) {
|
||||
this.formData[key] = data[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 设置选择器文本
|
||||
this.updatePickerTexts();
|
||||
}
|
||||
},
|
||||
|
||||
// 填充学生基本信息
|
||||
fillStudentInfo() {
|
||||
if (this.studentInfo) {
|
||||
this.formData.studentName = this.studentInfo.studentName || '';
|
||||
this.formData.studentNumber = this.studentInfo.studentNumber || '';
|
||||
this.formData.collegeName = this.studentInfo.collegeName || '';
|
||||
this.formData.majorName = this.studentInfo.majorName || '';
|
||||
this.formData.className = this.studentInfo.className || '';
|
||||
|
||||
// 如果是创建模式,填充其他基本信息
|
||||
if (this.mode === 'create') {
|
||||
this.formData.idCard = this.studentInfo.idCard || '';
|
||||
this.formData.contactPhone = this.studentInfo.contactPhone || '';
|
||||
this.formData.grade = this.studentInfo.grade || '';
|
||||
}
|
||||
|
||||
this.updatePickerTexts();
|
||||
}
|
||||
},
|
||||
|
||||
// 更新选择器文本显示
|
||||
updatePickerTexts() {
|
||||
// 更新年级文本
|
||||
if (this.formData.grade && this.gradeOptions[0].length > 0) {
|
||||
const gradeOption = this.gradeOptions[0].find(item => item.value === this.formData.grade);
|
||||
this.gradeText = gradeOption ? gradeOption.label : '';
|
||||
}
|
||||
|
||||
// 更新家庭经济情况文本
|
||||
if (this.formData.familyFinancialStatus && this.financialOptions[0].length > 0) {
|
||||
const financialOption = this.financialOptions[0].find(item => item.value === this.formData.familyFinancialStatus);
|
||||
this.financialText = financialOption ? financialOption.label : '';
|
||||
}
|
||||
},
|
||||
|
||||
// 年级选择确认
|
||||
onGradeConfirm(e) {
|
||||
const index = e.indexs[0];
|
||||
const selected = this.gradeOptions[0][index];
|
||||
this.formData.grade = selected.value;
|
||||
this.gradeText = selected.label;
|
||||
this.showGradePicker = false;
|
||||
},
|
||||
|
||||
// 家庭经济情况选择确认
|
||||
onFinancialConfirm(e) {
|
||||
const index = e.indexs[0];
|
||||
const selected = this.financialOptions[0][index];
|
||||
this.formData.familyFinancialStatus = selected.value;
|
||||
this.financialText = selected.label;
|
||||
this.showFinancialPicker = false;
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
validateForm() {
|
||||
const requiredFields = [
|
||||
{ field: 'studentName', name: '学生姓名' },
|
||||
{ field: 'studentNumber', name: '学号' },
|
||||
{ field: 'idCard', name: '身份证号' },
|
||||
{ field: 'contactPhone', name: '联系电话' },
|
||||
{ field: 'collegeName', name: '学院名称' },
|
||||
{ field: 'majorName', name: '专业名称' },
|
||||
{ field: 'className', name: '班级名称' },
|
||||
{ field: 'familyFinancialStatus', name: '家庭经济情况' },
|
||||
{ field: 'applicationReason', name: '申请理由' },
|
||||
{ field: 'personalAbility', name: '个人能力及经验' },
|
||||
{ field: 'timeArrangement', name: '时间安排' }
|
||||
];
|
||||
|
||||
for (const item of requiredFields) {
|
||||
if (!this.formData[item.field] || this.formData[item.field].trim() === '') {
|
||||
uni.showToast({
|
||||
title: `请填写${item.name}`,
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证身份证号格式
|
||||
if (this.formData.idCard && !/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(this.formData.idCard)) {
|
||||
uni.showToast({
|
||||
title: '身份证号格式不正确',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证手机号格式
|
||||
if (this.formData.contactPhone && !/^1[3-9]\d{9}$/.test(this.formData.contactPhone)) {
|
||||
uni.showToast({
|
||||
title: '手机号格式不正确',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// 保存草稿
|
||||
async saveDraft(autoNavigate = true) {
|
||||
if (!this.validateForm()) return false;
|
||||
|
||||
this.saving = true;
|
||||
|
||||
try {
|
||||
const requestData = {
|
||||
...this.formData,
|
||||
positionId: this.positionId,
|
||||
positionName: this.positionData.positionName,
|
||||
positionType: this.positionData.positionType || ''
|
||||
};
|
||||
|
||||
let response;
|
||||
if (this.mode === 'edit' && this.applicationId) {
|
||||
requestData.id = this.applicationId;
|
||||
response = await updateApplication(requestData);
|
||||
} else {
|
||||
response = await addApplication(requestData);
|
||||
}
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
if (autoNavigate) {
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1000);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(response.msg || '保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存草稿失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '保存失败',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 提交申请
|
||||
async submitApplication() {
|
||||
if (!this.validateForm()) return;
|
||||
|
||||
try {
|
||||
const { confirm } = await uni.showModal({
|
||||
title: '确认提交',
|
||||
content: '确定要提交申请吗?提交后将无法修改。',
|
||||
showCancel: true
|
||||
});
|
||||
|
||||
if (!confirm) return; // 用户取消
|
||||
|
||||
this.submitting = true;
|
||||
|
||||
// 先保存申请(不自动跳转)
|
||||
const saveSuccess = await this.saveDraft(false);
|
||||
|
||||
if (saveSuccess) {
|
||||
// 这里可以添加提交申请的逻辑
|
||||
// 如果后端有单独的提交接口,可以调用
|
||||
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('提交申请失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '提交失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.apply-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 120rpx; /* 为底部按钮留空间 */
|
||||
}
|
||||
|
||||
.position-card {
|
||||
background-color: #fff;
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.position-info {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #1890ff;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.position-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.position-detail text {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background-color: #fff;
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.form-section:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 12rpx;
|
||||
border-bottom: 2rpx solid #1890ff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.section-title::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2rpx;
|
||||
left: 0;
|
||||
width: 60rpx;
|
||||
height: 2rpx;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
display: flex;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.bottom-actions .u-button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 覆盖uview样式 */
|
||||
:deep(.u-form-item) {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
:deep(.u-form-item__body__left__content__label) {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.u-input__content__field-wrapper__field) {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
:deep(.u-textarea__count) {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,632 @@
|
||||
<template>
|
||||
<view class="detail-container">
|
||||
<!-- 岗位基本信息 -->
|
||||
<view class="info-card" v-if="positionData">
|
||||
<view class="card-header">
|
||||
<view class="position-title">
|
||||
<view class="position-name">{{ positionData.positionName }}</view>
|
||||
<view class="position-status">
|
||||
<u-tag
|
||||
:text="getStatusText(positionData.status)"
|
||||
:type="getStatusType(positionData.status)"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="publish-info">
|
||||
<text class="publish-scope">{{ positionData.positionScopeName }}</text>
|
||||
<text class="create-time">发布时间:{{ positionData.createTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心信息 -->
|
||||
<view class="core-info">
|
||||
<view class="info-item">
|
||||
<view class="info-label">
|
||||
<u-icon name="account" size="32" color="#1890ff" />
|
||||
<text>招录情况</text>
|
||||
</view>
|
||||
<view class="info-content">
|
||||
<view class="recruitment-info">
|
||||
<text class="recruitment-text">需求 {{ positionData.requiredCount }} 人</text>
|
||||
<text class="recruitment-text current">已招录 {{ positionData.currentCount || 0 }} 人</text>
|
||||
</view>
|
||||
<u-line-progress
|
||||
:percent="getRecruitmentProgress()"
|
||||
:active-color="getProgressColor()"
|
||||
height="12"
|
||||
:show-percent="false"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<view class="info-label">
|
||||
<u-icon name="clock" size="32" color="#1890ff" />
|
||||
<text>工作时间</text>
|
||||
</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ positionData.workTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<view class="info-label">
|
||||
<u-icon name="calendar" size="32" color="#1890ff" />
|
||||
<text>有效期限</text>
|
||||
</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ positionData.startDate }} 至 {{ positionData.endDate }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<view class="info-label">
|
||||
<u-icon name="account" size="32" color="#1890ff" />
|
||||
<text>联系老师</text>
|
||||
</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value">{{ positionData.contactTeacher }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item">
|
||||
<view class="info-label">
|
||||
<u-icon name="phone" size="32" color="#1890ff" />
|
||||
<text>联系电话</text>
|
||||
</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value contact-phone" @click="callPhone">{{ positionData.contactPhone }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-item" v-if="positionData.salaryInfo">
|
||||
<view class="info-label">
|
||||
<u-icon name="rmb-circle" size="32" color="#1890ff" />
|
||||
<text>薪资情况</text>
|
||||
</view>
|
||||
<view class="info-content">
|
||||
<text class="info-value salary">{{ positionData.salaryInfo }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 岗位要求 -->
|
||||
<view class="content-card" v-if="positionData && positionData.positionRequirements">
|
||||
<view class="card-title">
|
||||
<u-icon name="file-text" size="32" color="#1890ff" />
|
||||
<text>岗位要求</text>
|
||||
</view>
|
||||
<view class="content-text">{{ positionData.positionRequirements }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 工作内容 -->
|
||||
<view class="content-card" v-if="positionData && positionData.workContent">
|
||||
<view class="card-title">
|
||||
<u-icon name="list" size="32" color="#1890ff" />
|
||||
<text>工作内容</text>
|
||||
</view>
|
||||
<view class="content-text">{{ positionData.workContent }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请状态 -->
|
||||
<view class="status-card" v-if="applicationStatus">
|
||||
<view class="card-title">
|
||||
<u-icon name="info-circle" size="32" color="#1890ff" />
|
||||
<text>我的申请状态</text>
|
||||
</view>
|
||||
<view class="status-content">
|
||||
<view class="status-item">
|
||||
<text class="status-label">申请状态:</text>
|
||||
<u-tag
|
||||
:text="applicationStatus.applicationStatusText"
|
||||
:type="getApplicationStatusType(applicationStatus.applicationStatus)"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
<view class="status-item" v-if="applicationStatus.lastApplicationTime">
|
||||
<text class="status-label">申请时间:</text>
|
||||
<text class="status-value">{{ applicationStatus.lastApplicationTime }}</text>
|
||||
</view>
|
||||
<view class="status-actions" v-if="applicationStatus.canEdit || applicationStatus.canCancel">
|
||||
<u-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="editApplication"
|
||||
v-if="applicationStatus.canEdit"
|
||||
>
|
||||
编辑申请
|
||||
</u-button>
|
||||
<u-button
|
||||
type="error"
|
||||
size="small"
|
||||
@click="cancelApplication"
|
||||
v-if="applicationStatus.canCancel"
|
||||
style="margin-left: 20rpx;"
|
||||
>
|
||||
撤销申请
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 备注信息 -->
|
||||
<view class="content-card" v-if="positionData && positionData.remark">
|
||||
<view class="card-title">
|
||||
<u-icon name="chat" size="32" color="#1890ff" />
|
||||
<text>备注信息</text>
|
||||
</view>
|
||||
<view class="content-text">{{ positionData.remark }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<u-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="handleApply"
|
||||
:disabled="!canApply()"
|
||||
:loading="submitting"
|
||||
>
|
||||
{{ getApplyButtonText() }}
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<u-loading-page :loading="loading" loading-text="加载中..." />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getPositionWithApplicationStatus,
|
||||
cancelApplication
|
||||
} from '@/api/workStudy.js';
|
||||
|
||||
export default {
|
||||
name: 'WorkStudyDetail',
|
||||
data() {
|
||||
return {
|
||||
positionId: '',
|
||||
positionData: null,
|
||||
applicationStatus: null,
|
||||
loading: false,
|
||||
submitting: false
|
||||
};
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
if (options.id) {
|
||||
this.positionId = options.id;
|
||||
this.loadPositionDetail();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '岗位ID不能为空',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 加载岗位详情
|
||||
async loadPositionDetail() {
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const response = await getPositionWithApplicationStatus(this.positionId);
|
||||
|
||||
if (response.code === 200) {
|
||||
this.positionData = response.data.position;
|
||||
this.applicationStatus = response.data.applicationStatus;
|
||||
} else {
|
||||
throw new Error(response.msg || '获取岗位详情失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载岗位详情失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '加载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 申请岗位
|
||||
handleApply() {
|
||||
if (!this.canApply()) {
|
||||
uni.showToast({
|
||||
title: this.getApplyButtonText(),
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已有申请且可以编辑,则编辑申请
|
||||
if (this.applicationStatus && this.applicationStatus.hasApplication && this.applicationStatus.canEdit) {
|
||||
this.editApplication();
|
||||
return;
|
||||
}
|
||||
|
||||
// 否则新建申请
|
||||
uni.navigateTo({
|
||||
url: `/pages/workStudy/apply?positionId=${this.positionId}`
|
||||
});
|
||||
},
|
||||
|
||||
// 编辑申请
|
||||
editApplication() {
|
||||
if (this.applicationStatus && this.applicationStatus.applicationId) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/workStudy/apply?positionId=${this.positionId}&applicationId=${this.applicationStatus.applicationId}&mode=edit`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 撤销申请
|
||||
async cancelApplication() {
|
||||
if (!this.applicationStatus || !this.applicationStatus.applicationId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { confirm } = await uni.showModal({
|
||||
title: '确认撤销',
|
||||
content: '确定要撤销此申请吗?',
|
||||
showCancel: true
|
||||
});
|
||||
|
||||
if (!confirm) return; // 用户取消
|
||||
|
||||
this.submitting = true;
|
||||
const response = await cancelApplication(this.applicationStatus.applicationId);
|
||||
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: '撤销成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 重新加载数据
|
||||
setTimeout(() => {
|
||||
this.loadPositionDetail();
|
||||
}, 1000);
|
||||
} else {
|
||||
throw new Error(response.msg || '撤销失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('撤销申请失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '撤销失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 拨打电话
|
||||
callPhone() {
|
||||
if (this.positionData && this.positionData.contactPhone) {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: this.positionData.contactPhone,
|
||||
fail: (error) => {
|
||||
console.error('拨打电话失败:', error);
|
||||
uni.showToast({
|
||||
title: '拨打电话失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 获取状态文字
|
||||
getStatusText(status) {
|
||||
const statusMap = {
|
||||
'DRAFT': '草稿',
|
||||
'PUBLISHED': '已发布',
|
||||
'RECRUITING': '招录中',
|
||||
'FULL': '已满员',
|
||||
'EXPIRED': '已过期',
|
||||
'SUSPENDED': '已暂停',
|
||||
'CANCELLED': '已取消'
|
||||
};
|
||||
return statusMap[status] || '未知状态';
|
||||
},
|
||||
|
||||
// 获取状态类型
|
||||
getStatusType(status) {
|
||||
const typeMap = {
|
||||
'DRAFT': 'info',
|
||||
'PUBLISHED': 'warning',
|
||||
'RECRUITING': 'success',
|
||||
'FULL': 'primary',
|
||||
'EXPIRED': 'error',
|
||||
'SUSPENDED': 'warning',
|
||||
'CANCELLED': 'error'
|
||||
};
|
||||
return typeMap[status] || 'default';
|
||||
},
|
||||
|
||||
// 获取招录进度
|
||||
getRecruitmentProgress() {
|
||||
if (!this.positionData || !this.positionData.requiredCount) return 0;
|
||||
const current = this.positionData.currentCount || 0;
|
||||
const required = this.positionData.requiredCount;
|
||||
return Math.min(Math.round((current / required) * 100), 100);
|
||||
},
|
||||
|
||||
// 获取进度条颜色
|
||||
getProgressColor() {
|
||||
const progress = this.getRecruitmentProgress();
|
||||
if (progress >= 100) return '#f5222d';
|
||||
if (progress >= 80) return '#fa8c16';
|
||||
if (progress >= 50) return '#1890ff';
|
||||
return '#52c41a';
|
||||
},
|
||||
|
||||
// 判断是否可以申请
|
||||
canApply() {
|
||||
if (!this.positionData) return false;
|
||||
|
||||
// 岗位状态必须是招录中
|
||||
if (this.positionData.status !== 'RECRUITING') return false;
|
||||
|
||||
// 如果已有申请,判断是否可以重新申请
|
||||
if (this.applicationStatus && this.applicationStatus.hasApplication) {
|
||||
// 如果申请被拒绝,可以重新申请
|
||||
return this.applicationStatus.applicationStatus === 'FINAL_REJECTED' ||
|
||||
this.applicationStatus.applicationStatus === 'COLLEGE_REJECTED';
|
||||
}
|
||||
|
||||
// 检查是否已满员
|
||||
const current = this.positionData.currentCount || 0;
|
||||
const required = this.positionData.requiredCount || 0;
|
||||
return current < required;
|
||||
},
|
||||
|
||||
// 获取申请按钮文字
|
||||
getApplyButtonText() {
|
||||
if (!this.positionData) return '加载中...';
|
||||
|
||||
if (this.positionData.status !== 'RECRUITING') {
|
||||
return '岗位暂不可申请';
|
||||
}
|
||||
|
||||
// 检查是否已满员
|
||||
const current = this.positionData.currentCount || 0;
|
||||
const required = this.positionData.requiredCount || 0;
|
||||
if (current >= required) {
|
||||
return '岗位已满员';
|
||||
}
|
||||
|
||||
// 如果有申请记录
|
||||
if (this.applicationStatus && this.applicationStatus.hasApplication) {
|
||||
const status = this.applicationStatus.applicationStatus;
|
||||
|
||||
if (status === 'DRAFT') {
|
||||
return '完善申请信息';
|
||||
} else if (status === 'SUBMITTED' || status === 'COLLEGE_REVIEWING' || status === 'FINAL_REVIEWING') {
|
||||
return '申请审核中';
|
||||
} else if (status === 'FINAL_APPROVED') {
|
||||
return '申请已通过';
|
||||
} else if (status === 'FINAL_REJECTED' || status === 'COLLEGE_REJECTED') {
|
||||
return '重新申请';
|
||||
} else if (status === 'CANCELLED') {
|
||||
return '重新申请';
|
||||
}
|
||||
|
||||
return '查看申请状态';
|
||||
}
|
||||
|
||||
return '申请此岗位';
|
||||
},
|
||||
|
||||
// 获取申请状态类型
|
||||
getApplicationStatusType(status) {
|
||||
const typeMap = {
|
||||
'DRAFT': 'info',
|
||||
'SUBMITTED': 'warning',
|
||||
'COLLEGE_REVIEWING': 'warning',
|
||||
'COLLEGE_APPROVED': 'success',
|
||||
'COLLEGE_REJECTED': 'error',
|
||||
'FINAL_REVIEWING': 'warning',
|
||||
'FINAL_APPROVED': 'success',
|
||||
'FINAL_REJECTED': 'error',
|
||||
'CANCELLED': 'info'
|
||||
};
|
||||
return typeMap[status] || 'default';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 120rpx; /* 为底部按钮留空间 */
|
||||
}
|
||||
|
||||
.info-card, .content-card, .status-card {
|
||||
background-color: #fff;
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.position-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.position-status {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.publish-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.publish-scope {
|
||||
font-size: 28rpx;
|
||||
color: #1890ff;
|
||||
padding: 8rpx 16rpx;
|
||||
background-color: #e6f7ff;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.create-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.core-info {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.info-label text {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.info-content {
|
||||
margin-left: 44rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.contact-phone {
|
||||
color: #1890ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.salary {
|
||||
color: #f5222d;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.recruitment-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.recruitment-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.recruitment-text.current {
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.card-title text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.status-content {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.status-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.status-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-actions {
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
z-index: 100;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,852 @@
|
||||
<template>
|
||||
<view class="work-study-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-bar">
|
||||
<u-search
|
||||
v-model="searchKeyword"
|
||||
placeholder="搜索岗位名称或联系老师"
|
||||
:show-action="false"
|
||||
@search="handleSearch"
|
||||
@custom="handleSearch"
|
||||
bg-color="#f6f6f6"
|
||||
height="72"
|
||||
shape="round"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 标签页 -->
|
||||
<view class="tabs-container">
|
||||
<u-tabs
|
||||
:list="tabsList"
|
||||
:current="currentTab"
|
||||
@change="onTabChange"
|
||||
active-color="#1890ff"
|
||||
inactive-color="#999"
|
||||
bar-width="40"
|
||||
bar-height="4"
|
||||
font-size="30"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 岗位列表 -->
|
||||
<view class="list-container" v-if="currentTab === 0">
|
||||
<!-- 筛选条件 -->
|
||||
<view class="filter-bar" v-if="showFilter">
|
||||
<view class="filter-item">
|
||||
<view @click="showScopePicker = true">
|
||||
<u-input
|
||||
v-model="scopeText"
|
||||
placeholder="选择发布范围"
|
||||
readonly
|
||||
border="surround"
|
||||
suffix-icon="arrow-down"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-item">
|
||||
<view @click="showStatusPicker = true">
|
||||
<u-input
|
||||
v-model="statusText"
|
||||
placeholder="选择岗位状态"
|
||||
readonly
|
||||
border="surround"
|
||||
suffix-icon="arrow-down"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-actions">
|
||||
<u-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleFilter"
|
||||
:loading="loading"
|
||||
>
|
||||
筛选
|
||||
</u-button>
|
||||
<u-button
|
||||
type="default"
|
||||
size="small"
|
||||
@click="resetFilter"
|
||||
style="margin-left: 10rpx;"
|
||||
>
|
||||
重置
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选按钮 -->
|
||||
<view class="action-bar">
|
||||
<u-button
|
||||
type="default"
|
||||
size="small"
|
||||
:icon="showFilter ? 'arrow-up' : 'arrow-down'"
|
||||
@click="showFilter = !showFilter"
|
||||
>
|
||||
{{ showFilter ? '收起筛选' : '展开筛选' }}
|
||||
</u-button>
|
||||
<u-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="reload"
|
||||
@click="refreshData"
|
||||
:loading="refreshing"
|
||||
>
|
||||
刷新
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 岗位卡片列表 -->
|
||||
<view class="list-content" v-if="positionList.length > 0">
|
||||
<view
|
||||
class="position-card"
|
||||
v-for="item in positionList"
|
||||
:key="item.id"
|
||||
@click="handleViewDetail(item)"
|
||||
>
|
||||
<!-- 卡片头部 -->
|
||||
<view class="card-header">
|
||||
<view class="position-info">
|
||||
<view class="position-name">{{ item.positionName }}</view>
|
||||
<view class="position-type">{{ item.positionScopeName || '未设置' }}</view>
|
||||
</view>
|
||||
<view class="status-badge">
|
||||
<u-tag
|
||||
:text="item.statusName || '未知'"
|
||||
:type="getStatusType(item.status)"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 岗位信息 -->
|
||||
<view class="card-content">
|
||||
<view class="info-row">
|
||||
<u-icon name="account" size="28" color="#666" />
|
||||
<text class="info-text">需求人数:{{ item.requiredCount }}人</text>
|
||||
<text class="info-text current-count">已招录:{{ item.currentCount || 0 }}人</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<u-icon name="clock" size="28" color="#666" />
|
||||
<text class="info-text">工作时间:{{ item.workTime }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<u-icon name="map" size="28" color="#666" />
|
||||
<text class="info-text">联系老师:{{ item.contactTeacher }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<u-icon name="phone" size="28" color="#666" />
|
||||
<text class="info-text">联系电话:{{ item.contactPhone }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<u-icon name="calendar" size="28" color="#666" />
|
||||
<text class="info-text">有效期:{{ item.startDate }} 至 {{ item.endDate }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="card-actions">
|
||||
<u-button
|
||||
type="default"
|
||||
size="small"
|
||||
@click.stop="handleViewDetail($event, item)"
|
||||
>
|
||||
查看详情
|
||||
</u-button>
|
||||
<u-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleApply($event, item)"
|
||||
:disabled="!canApply(item)"
|
||||
style="margin-left: 20rpx;"
|
||||
>
|
||||
{{ getApplyButtonText(item) }}
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else-if="!loading">
|
||||
<u-empty
|
||||
text="暂无岗位信息"
|
||||
icon="search"
|
||||
:show="true"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view class="load-more" v-if="hasMore && positionList.length > 0">
|
||||
<u-loadmore
|
||||
:status="loadMoreStatus"
|
||||
:load-text="loadText"
|
||||
@loadmore="loadMore"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的申请列表 -->
|
||||
<view class="list-container" v-if="currentTab === 1">
|
||||
<view class="list-content" v-if="applicationList.length > 0">
|
||||
<view
|
||||
class="application-card"
|
||||
v-for="item in applicationList"
|
||||
:key="item.id"
|
||||
@click="handleViewApplication(item)"
|
||||
>
|
||||
<!-- 申请信息 -->
|
||||
<view class="card-header">
|
||||
<view class="application-info">
|
||||
<view class="position-name">{{ item.positionName }}</view>
|
||||
<view class="apply-time">申请时间:{{ item.createTime }}</view>
|
||||
</view>
|
||||
<view class="status-badge">
|
||||
<u-tag
|
||||
:text="getApplicationStatusText(item)"
|
||||
:type="getApplicationStatusType(item)"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 申请状态 -->
|
||||
<view class="card-content">
|
||||
<view class="info-row">
|
||||
<u-icon name="file-text" size="28" color="#666" />
|
||||
<text class="info-text">申请状态:{{ getApplicationStatusText(item) }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="item.collegeReviewStatus">
|
||||
<u-icon name="checkmark-circle" size="28" color="#666" />
|
||||
<text class="info-text">学院审核:{{ getReviewStatusText(item.collegeReviewStatus) }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="item.finalReviewStatus">
|
||||
<u-icon name="checkmark-circle" size="28" color="#666" />
|
||||
<text class="info-text">学生处审核:{{ getReviewStatusText(item.finalReviewStatus) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="card-actions">
|
||||
<u-button
|
||||
type="default"
|
||||
size="small"
|
||||
@click.stop="handleViewApplication($event, item)"
|
||||
>
|
||||
查看详情
|
||||
</u-button>
|
||||
<u-button
|
||||
type="warning"
|
||||
size="small"
|
||||
@click.stop="handleCancelApplication($event, item)"
|
||||
v-if="canCancelApplication(item)"
|
||||
style="margin-left: 20rpx;"
|
||||
>
|
||||
撤销申请
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else-if="!loading">
|
||||
<u-empty
|
||||
text="暂无申请记录"
|
||||
icon="file-text"
|
||||
:show="true"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 发布范围选择器 -->
|
||||
<u-picker
|
||||
:show="showScopePicker"
|
||||
:columns="scopeOptions"
|
||||
keyName="label"
|
||||
@confirm="onScopeConfirm"
|
||||
@cancel="showScopePicker = false"
|
||||
/>
|
||||
|
||||
<!-- 状态选择器 -->
|
||||
<u-picker
|
||||
:show="showStatusPicker"
|
||||
:columns="statusOptions"
|
||||
keyName="label"
|
||||
@confirm="onStatusConfirm"
|
||||
@cancel="showStatusPicker = false"
|
||||
/>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<u-loading-page :loading="loading" loading-text="加载中..." />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getAvailablePositions,
|
||||
getMyApplications,
|
||||
cancelApplication,
|
||||
getCurrentStudentInfo
|
||||
} from '@/api/workStudy.js';
|
||||
|
||||
export default {
|
||||
name: 'WorkStudyIndex',
|
||||
data() {
|
||||
return {
|
||||
// 搜索关键词
|
||||
searchKeyword: '',
|
||||
|
||||
// 标签页
|
||||
currentTab: 0, // 确保是数字类型
|
||||
tabsList: [
|
||||
{ name: '可申请岗位' },
|
||||
{ name: '我的申请' }
|
||||
],
|
||||
|
||||
// 筛选条件
|
||||
showFilter: false,
|
||||
showScopePicker: false,
|
||||
showStatusPicker: false,
|
||||
scopeText: '',
|
||||
statusText: '',
|
||||
|
||||
// 选择器选项
|
||||
scopeOptions: [
|
||||
[
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '本学院', value: 'COLLEGE' },
|
||||
{ label: '全校', value: 'UNIVERSITY' }
|
||||
]
|
||||
],
|
||||
statusOptions: [
|
||||
[
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '已发布', value: 'PUBLISHED' },
|
||||
{ label: '招录中', value: 'RECRUITING' },
|
||||
{ label: '已暂停', value: 'SUSPENDED' }
|
||||
]
|
||||
],
|
||||
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
positionName: '',
|
||||
positionScope: '',
|
||||
status: ''
|
||||
},
|
||||
|
||||
// 列表数据
|
||||
positionList: [],
|
||||
applicationList: [],
|
||||
|
||||
// 分页状态
|
||||
hasMore: true,
|
||||
loadMoreStatus: 'loadmore',
|
||||
loadText: {
|
||||
loadmore: '点击或上拉加载更多',
|
||||
loading: '正在加载...',
|
||||
nomore: '没有更多了'
|
||||
},
|
||||
|
||||
// 加载状态
|
||||
loading: false,
|
||||
refreshing: false,
|
||||
|
||||
// 用户信息
|
||||
studentInfo: null
|
||||
};
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// 确保currentTab是数字类型
|
||||
this.currentTab = Number(this.currentTab);
|
||||
this.initData();
|
||||
},
|
||||
|
||||
onReady() {
|
||||
// 页面渲染完成后再次确保数据类型正确
|
||||
this.$nextTick(() => {
|
||||
this.currentTab = Number(this.currentTab);
|
||||
});
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 如果是从申请页面返回,刷新数据
|
||||
if (this.currentTab === 1) {
|
||||
this.loadMyApplications(true);
|
||||
}
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.refreshData();
|
||||
},
|
||||
|
||||
// 上拉加载更多
|
||||
onReachBottom() {
|
||||
if (this.currentTab === 0 && this.hasMore && !this.loading) {
|
||||
this.loadMore();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化数据
|
||||
async initData() {
|
||||
try {
|
||||
// 获取学生信息
|
||||
await this.loadStudentInfo();
|
||||
// 加载岗位列表
|
||||
await this.loadPositionList(true);
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error);
|
||||
uni.showToast({
|
||||
title: '加载数据失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 获取学生信息
|
||||
async loadStudentInfo() {
|
||||
try {
|
||||
const response = await getCurrentStudentInfo();
|
||||
if (response.code === 200) {
|
||||
this.studentInfo = response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取学生信息失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 加载岗位列表
|
||||
async loadPositionList(reset = false) {
|
||||
if (this.loading) return;
|
||||
|
||||
if (reset) {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.positionList = [];
|
||||
this.hasMore = true;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
this.loadMoreStatus = 'loading';
|
||||
|
||||
try {
|
||||
const response = await getAvailablePositions(this.queryParams);
|
||||
|
||||
if (response.code === 200) {
|
||||
const newList = response.rows || [];
|
||||
|
||||
if (reset) {
|
||||
this.positionList = newList;
|
||||
} else {
|
||||
this.positionList = [...this.positionList, ...newList];
|
||||
}
|
||||
|
||||
// 检查是否还有更多数据
|
||||
if (newList.length < this.queryParams.pageSize) {
|
||||
this.hasMore = false;
|
||||
this.loadMoreStatus = 'nomore';
|
||||
} else {
|
||||
this.loadMoreStatus = 'loadmore';
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.msg || '获取岗位列表失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载岗位列表失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '加载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
this.loadMoreStatus = 'loadmore';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
uni.stopPullDownRefresh();
|
||||
}
|
||||
},
|
||||
|
||||
// 加载我的申请列表
|
||||
async loadMyApplications(reset = false) {
|
||||
if (this.loading) return;
|
||||
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const response = await getMyApplications();
|
||||
|
||||
if (response.code === 200) {
|
||||
this.applicationList = response.data || [];
|
||||
} else {
|
||||
throw new Error(response.msg || '获取申请列表失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载申请列表失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '加载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.loading = false;
|
||||
uni.stopPullDownRefresh();
|
||||
}
|
||||
},
|
||||
|
||||
// 标签页切换
|
||||
onTabChange(index) {
|
||||
// 确保index是数字类型
|
||||
const tabIndex = typeof index === 'object' ? index.index : index;
|
||||
this.currentTab = Number(tabIndex);
|
||||
|
||||
// 延迟执行,确保DOM渲染完成
|
||||
this.$nextTick(() => {
|
||||
if (this.currentTab === 0) {
|
||||
this.loadPositionList(true);
|
||||
} else if (this.currentTab === 1) {
|
||||
this.loadMyApplications(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.queryParams.positionName = this.searchKeyword;
|
||||
this.loadPositionList(true);
|
||||
},
|
||||
|
||||
// 筛选
|
||||
handleFilter() {
|
||||
this.loadPositionList(true);
|
||||
},
|
||||
|
||||
// 重置筛选
|
||||
resetFilter() {
|
||||
this.queryParams.positionScope = '';
|
||||
this.queryParams.status = '';
|
||||
this.scopeText = '';
|
||||
this.statusText = '';
|
||||
this.searchKeyword = '';
|
||||
this.queryParams.positionName = '';
|
||||
this.loadPositionList(true);
|
||||
},
|
||||
|
||||
// 刷新数据
|
||||
refreshData() {
|
||||
this.refreshing = true;
|
||||
if (this.currentTab === 0) {
|
||||
this.loadPositionList(true).finally(() => {
|
||||
this.refreshing = false;
|
||||
});
|
||||
} else {
|
||||
this.loadMyApplications(true).finally(() => {
|
||||
this.refreshing = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 加载更多
|
||||
loadMore() {
|
||||
if (!this.hasMore || this.loading) return;
|
||||
|
||||
this.queryParams.pageNum++;
|
||||
this.loadPositionList(false);
|
||||
},
|
||||
|
||||
// 查看岗位详情
|
||||
handleViewDetail(event, item) {
|
||||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||||
if (!item && typeof event === 'object' && event.id) {
|
||||
item = event;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/workStudy/detail?id=${item.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 申请岗位
|
||||
handleApply(event, item) {
|
||||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||||
if (!item && typeof event === 'object' && event.id) {
|
||||
item = event;
|
||||
}
|
||||
|
||||
if (!this.canApply(item)) {
|
||||
uni.showToast({
|
||||
title: this.getApplyButtonText(item),
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/workStudy/apply?positionId=${item.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 查看申请详情
|
||||
handleViewApplication(event, item) {
|
||||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||||
if (!item && typeof event === 'object' && event.id) {
|
||||
item = event;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/workStudy/applicationDetail?id=${item.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 撤销申请
|
||||
async handleCancelApplication(event, item) {
|
||||
// 如果只传了一个参数,说明是从卡片点击调用的,第一个参数就是item
|
||||
if (!item && typeof event === 'object' && event.id) {
|
||||
item = event;
|
||||
}
|
||||
try {
|
||||
const { confirm } = await uni.showModal({
|
||||
title: '确认撤销',
|
||||
content: '确定要撤销此申请吗?',
|
||||
showCancel: true
|
||||
});
|
||||
|
||||
if (!confirm) return; // 用户取消
|
||||
|
||||
const response = await cancelApplication(item.id);
|
||||
if (response.code === 200) {
|
||||
uni.showToast({
|
||||
title: '撤销成功',
|
||||
icon: 'success'
|
||||
});
|
||||
this.loadMyApplications(true);
|
||||
} else {
|
||||
throw new Error(response.msg || '撤销失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('撤销申请失败:', error);
|
||||
uni.showToast({
|
||||
title: error.message || '撤销失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 发布范围选择确认
|
||||
onScopeConfirm(e) {
|
||||
const index = e.indexs[0];
|
||||
const selected = this.scopeOptions[0][index];
|
||||
this.queryParams.positionScope = selected.value;
|
||||
this.scopeText = selected.label;
|
||||
this.showScopePicker = false;
|
||||
},
|
||||
|
||||
// 状态选择确认
|
||||
onStatusConfirm(e) {
|
||||
const index = e.indexs[0];
|
||||
const selected = this.statusOptions[0][index];
|
||||
this.queryParams.status = selected.value;
|
||||
this.statusText = selected.label;
|
||||
this.showStatusPicker = false;
|
||||
},
|
||||
|
||||
// 获取状态类型
|
||||
getStatusType(status) {
|
||||
const typeMap = {
|
||||
'DRAFT': 'info',
|
||||
'PUBLISHED': 'warning',
|
||||
'RECRUITING': 'success',
|
||||
'FULL': 'primary',
|
||||
'EXPIRED': 'error',
|
||||
'SUSPENDED': 'warning',
|
||||
'CANCELLED': 'error'
|
||||
};
|
||||
return typeMap[status] || 'default';
|
||||
},
|
||||
|
||||
// 判断是否可以申请
|
||||
canApply(item) {
|
||||
return item.status === 'RECRUITING' &&
|
||||
(item.currentCount || 0) < (item.requiredCount || 0);
|
||||
},
|
||||
|
||||
// 获取申请按钮文字
|
||||
getApplyButtonText(item) {
|
||||
if (item.status !== 'RECRUITING') {
|
||||
return '暂不可申请';
|
||||
}
|
||||
if ((item.currentCount || 0) >= (item.requiredCount || 0)) {
|
||||
return '已满员';
|
||||
}
|
||||
return '申请岗位';
|
||||
},
|
||||
|
||||
// 获取申请状态文字
|
||||
getApplicationStatusText(item) {
|
||||
const statusMap = {
|
||||
'DRAFT': '草稿',
|
||||
'SUBMITTED': '已提交',
|
||||
'COLLEGE_REVIEWING': '学院审核中',
|
||||
'COLLEGE_APPROVED': '学院审核通过',
|
||||
'COLLEGE_REJECTED': '学院审核未通过',
|
||||
'FINAL_REVIEWING': '学生处审核中',
|
||||
'FINAL_APPROVED': '审核通过',
|
||||
'FINAL_REJECTED': '审核未通过',
|
||||
'CANCELLED': '已撤销'
|
||||
};
|
||||
return statusMap[item.status] || '未知状态';
|
||||
},
|
||||
|
||||
// 获取申请状态类型
|
||||
getApplicationStatusType(item) {
|
||||
const typeMap = {
|
||||
'DRAFT': 'info',
|
||||
'SUBMITTED': 'warning',
|
||||
'COLLEGE_REVIEWING': 'warning',
|
||||
'COLLEGE_APPROVED': 'success',
|
||||
'COLLEGE_REJECTED': 'error',
|
||||
'FINAL_REVIEWING': 'warning',
|
||||
'FINAL_APPROVED': 'success',
|
||||
'FINAL_REJECTED': 'error',
|
||||
'CANCELLED': 'info'
|
||||
};
|
||||
return typeMap[item.status] || 'default';
|
||||
},
|
||||
|
||||
// 获取审核状态文字
|
||||
getReviewStatusText(status) {
|
||||
const statusMap = {
|
||||
'PENDING': '待审核',
|
||||
'APPROVED': '通过',
|
||||
'REJECTED': '未通过'
|
||||
};
|
||||
return statusMap[status] || '未知';
|
||||
},
|
||||
|
||||
// 判断是否可以撤销申请
|
||||
canCancelApplication(item) {
|
||||
return ['DRAFT', 'SUBMITTED', 'COLLEGE_REVIEWING'].includes(item.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.work-study-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
background-color: #fff;
|
||||
padding: 20rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.filter-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.list-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.position-card, .application-card {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.position-info, .application-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.position-type, .apply-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-left: 12rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.current-count {
|
||||
margin-left: 20rpx;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
border-top: 1rpx solid #eee;
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 80rpx 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,87 +1,536 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="page-header">
|
||||
<text class="page-title">考核申请</text>
|
||||
</view>
|
||||
<view class="page-container">
|
||||
<!-- 顶部导航 -->
|
||||
<u-navbar title="考核申请" :border-bottom="false" bg-color="#3c9cff" title-color="#fff">
|
||||
<view slot="left" @click="goBack">
|
||||
<u-icon name="arrow-left" color="#fff" size="22"></u-icon>
|
||||
</view>
|
||||
</u-navbar>
|
||||
|
||||
<view class="content">
|
||||
<view class="notice-card">
|
||||
<u-icon name="info-circle" size="20" color="#1890ff" />
|
||||
<text class="notice-text">考核申请功能正在开发中...</text>
|
||||
<!-- 加载状态 -->
|
||||
<u-loading-page :loading="loading" loading-text="加载中..."></u-loading-page>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<view v-if="!loading" class="content-wrapper">
|
||||
<!-- 空状态 -->
|
||||
<view v-if="assessmentScheduleList.length === 0" class="empty-container">
|
||||
<u-empty text="暂无可申请的考核计划" mode="data"></u-empty>
|
||||
</view>
|
||||
|
||||
<!-- 这里可以添加考核申请的具体内容 -->
|
||||
<view class="form-section">
|
||||
<!-- 申请表单内容将在这里添加 -->
|
||||
<!-- 考核计划列表 -->
|
||||
<view v-else class="schedule-list">
|
||||
<view
|
||||
v-for="(item, index) in assessmentScheduleList"
|
||||
:key="item.id || index"
|
||||
class="schedule-card"
|
||||
>
|
||||
<!-- 卡片头部 -->
|
||||
<view class="card-header">
|
||||
<view class="schedule-info">
|
||||
<text class="schedule-name">{{ item.scheduleName || '暂无' }}</text>
|
||||
<view class="schedule-meta">
|
||||
<text class="academic-info">
|
||||
{{ item.academicYear || '暂无' }}
|
||||
{{ getSemesterText(item.semester) }}
|
||||
</text>
|
||||
<u-tag
|
||||
:text="getStatusText(item.status)"
|
||||
:type="getStatusTagType(item.status)"
|
||||
size="mini"
|
||||
></u-tag>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 卡片内容 -->
|
||||
<view class="card-content">
|
||||
<view class="schedule-description">
|
||||
<text class="description-text">
|
||||
{{ item.description || '暂无说明' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="time-info">
|
||||
<view class="time-item">
|
||||
<text class="time-label">开始时间:</text>
|
||||
<text class="time-value">{{ formatTime(item.startTime) }}</text>
|
||||
</view>
|
||||
<view class="time-item">
|
||||
<text class="time-label">结束时间:</text>
|
||||
<text class="time-value">{{ formatTime(item.endTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="plan-info">
|
||||
<text class="plan-name">考核方案: {{ item.planName || '暂无' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 卡片操作按钮 -->
|
||||
<view class="card-actions">
|
||||
<view class="action-btn info-btn" @click="handleViewSchedule(item)">
|
||||
<u-icon name="eye" size="20" color="#3c9cff"></u-icon>
|
||||
<text class="btn-text">查看计划</text>
|
||||
</view>
|
||||
<view
|
||||
v-if="canSubmitApplication(item)"
|
||||
class="action-btn success-btn"
|
||||
@click="handleSubmitApplication(item)"
|
||||
>
|
||||
<u-icon name="edit-pen" size="20" color="#5ac725"></u-icon>
|
||||
<text class="btn-text">提交申请</text>
|
||||
</view>
|
||||
<view class="action-btn warning-btn" @click="handleViewApplication(item)">
|
||||
<u-icon name="file-text" size="20" color="#ff9900"></u-icon>
|
||||
<text class="btn-text">查看申请</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分页加载 -->
|
||||
<view v-if="hasMore && assessmentScheduleList.length > 0" class="load-more">
|
||||
<u-loadmore :status="loadStatus" @loadmore="loadMore"></u-loadmore>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { request } from '@/common/request.js';
|
||||
import { getDictLabel, getDictTagType, getDict } from '@/common/dict.js';
|
||||
|
||||
export default {
|
||||
name: 'AssessmentApply',
|
||||
data() {
|
||||
return {
|
||||
// 页面数据
|
||||
loading: false,
|
||||
assessmentScheduleList: [],
|
||||
total: 0,
|
||||
hasMore: true,
|
||||
loadStatus: 'loadmore',
|
||||
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
statusList: ['2', '3'], // 只查询进行中和已结束的考核计划
|
||||
},
|
||||
|
||||
// 字典数据
|
||||
assessmentScheduleStatus: [],
|
||||
studentSemester: [],
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
// 页面加载时的处理
|
||||
async onLoad(options) {
|
||||
console.log('考核申请页面加载');
|
||||
await this.loadDictData();
|
||||
await this.getList();
|
||||
},
|
||||
onShow() {
|
||||
// 从其他页面返回时刷新列表
|
||||
if (this.assessmentScheduleList.length > 0) {
|
||||
this.handleSuccess();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 页面方法
|
||||
// 返回上一页
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
|
||||
// 加载字典数据
|
||||
async loadDictData() {
|
||||
try {
|
||||
this.assessmentScheduleStatus = await getDict('assessment_schedule_status');
|
||||
this.studentSemester = await getDict('student_semester');
|
||||
} catch (error) {
|
||||
console.error('加载字典数据失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取考核计划列表
|
||||
async getList(loadMore = false) {
|
||||
if (!loadMore) {
|
||||
this.loading = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/assessment/schedule/listByStatus',
|
||||
method: 'GET',
|
||||
params: this.queryParams,
|
||||
});
|
||||
|
||||
if (res && res.code === 200) {
|
||||
const rows = res.rows || [];
|
||||
|
||||
if (loadMore) {
|
||||
this.assessmentScheduleList = this.assessmentScheduleList.concat(rows);
|
||||
} else {
|
||||
this.assessmentScheduleList = rows;
|
||||
}
|
||||
|
||||
this.total = res.total || 0;
|
||||
|
||||
if (rows.length < this.queryParams.pageSize) {
|
||||
this.hasMore = false;
|
||||
this.loadStatus = 'nomore';
|
||||
} else {
|
||||
this.hasMore = true;
|
||||
this.loadStatus = 'loadmore';
|
||||
}
|
||||
} else {
|
||||
this.handleRequestError(res?.msg || '获取数据失败', loadMore);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取数据失败:', error);
|
||||
this.handleRequestError('获取数据失败', loadMore);
|
||||
} finally {
|
||||
if (!loadMore) {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 错误处理
|
||||
handleRequestError(message, isLoadMore = false) {
|
||||
if (!isLoadMore) {
|
||||
this.assessmentScheduleList = [];
|
||||
this.total = 0;
|
||||
}
|
||||
this.hasMore = false;
|
||||
this.loadStatus = 'nomore';
|
||||
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none',
|
||||
});
|
||||
},
|
||||
|
||||
// 加载更多
|
||||
async loadMore() {
|
||||
if (!this.hasMore || this.loadStatus !== 'loadmore') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadStatus = 'loading';
|
||||
this.queryParams.pageNum += 1;
|
||||
|
||||
try {
|
||||
await this.getList(true);
|
||||
} catch (error) {
|
||||
console.error('加载更多数据失败:', error);
|
||||
this.queryParams.pageNum -= 1;
|
||||
this.loadStatus = 'loadmore';
|
||||
}
|
||||
},
|
||||
|
||||
// 查看考核计划信息
|
||||
handleViewSchedule(row) {
|
||||
const message = `考核计划:${row.scheduleName}\n说明:${row.description}\n时间:${row.startTime} 至 ${row.endTime}`;
|
||||
uni.showModal({
|
||||
title: '考核计划信息',
|
||||
content: message,
|
||||
showCancel: false,
|
||||
});
|
||||
},
|
||||
|
||||
// 判断是否可以提交申请
|
||||
canSubmitApplication(row) {
|
||||
const now = new Date();
|
||||
const startTime = new Date(row.startTime);
|
||||
const endTime = new Date(row.endTime);
|
||||
return row.status === '2' && now >= startTime && now <= endTime;
|
||||
},
|
||||
|
||||
// 提交考核申请
|
||||
async handleSubmitApplication(row) {
|
||||
try {
|
||||
// 先获取当前用户的学生信息
|
||||
const response = await request({
|
||||
url: '/studentMsg/studentMsg/personalInfo',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
const studentInfo = response.data;
|
||||
|
||||
// 检查用户是否已经填写过申请
|
||||
const existingApplication = await request({
|
||||
url: `/assessment/application/student/${studentInfo.id}/schedule/${row.id}`,
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
console.log('existingApplication:', existingApplication);
|
||||
if (existingApplication.code === 200 && existingApplication.data) {
|
||||
// 用户已经填写过申请,跳转到编辑页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/xskh/khsq/form?id=${existingApplication.data.id}&title=编辑考核申请&scheduleId=${row.id}`,
|
||||
});
|
||||
} else {
|
||||
// 用户没有填写过申请,跳转到新增页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/xskh/khsq/form?title=提交考核申请&scheduleId=${row.id}`,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 获取学生信息失败,按新增模式处理
|
||||
uni.navigateTo({
|
||||
url: `/pages/xskh/khsq/form?title=提交考核申请&scheduleId=${row.id}`,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查用户申请记录失败:', error);
|
||||
// 检查失败时,按新增模式处理
|
||||
uni.navigateTo({
|
||||
url: `/pages/xskh/khsq/form?title=提交考核申请&scheduleId=${row.id}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 查看考核申请
|
||||
async handleViewApplication(row) {
|
||||
try {
|
||||
// 先获取当前用户的学生信息
|
||||
const response = await request({
|
||||
url: '/studentMsg/studentMsg/personalInfo',
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
const studentInfo = response.data;
|
||||
|
||||
// 检查用户是否已经填写过申请
|
||||
const existingApplication = await request({
|
||||
url: `/assessment/application/student/${studentInfo.id}/schedule/${row.id}`,
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
if (existingApplication.code === 200 && existingApplication.data) {
|
||||
// 用户已经填写过申请,跳转到查看页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/xskh/khsq/form?id=${existingApplication.data.id}&title=查看考核申请&scheduleId=${row.id}&viewMode=true`,
|
||||
});
|
||||
} else {
|
||||
// 用户没有填写过申请,显示提示信息
|
||||
uni.showToast({
|
||||
title: '您还没有提交过该考核计划的申请',
|
||||
icon: 'none',
|
||||
});
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '获取用户信息失败,无法查看申请',
|
||||
icon: 'none',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查用户申请记录失败:', error);
|
||||
uni.showToast({
|
||||
title: '检查申请记录失败,请稍后重试',
|
||||
icon: 'none',
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 提交成功回调
|
||||
handleSuccess() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.hasMore = true;
|
||||
this.loadStatus = 'loadmore';
|
||||
this.getList();
|
||||
},
|
||||
|
||||
// 时间格式化
|
||||
formatTime(timeStr) {
|
||||
if (!timeStr) return '-';
|
||||
|
||||
try {
|
||||
const date = new Date(timeStr);
|
||||
if (isNaN(date.getTime())) return timeStr;
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
} catch (error) {
|
||||
console.error('时间格式化失败:', error);
|
||||
return timeStr;
|
||||
}
|
||||
},
|
||||
|
||||
// 获取学期文本
|
||||
getSemesterText(semester) {
|
||||
return getDictLabel(this.studentSemester, semester) || '暂无';
|
||||
},
|
||||
|
||||
// 获取状态文本
|
||||
getStatusText(status) {
|
||||
return getDictLabel(this.assessmentScheduleStatus, status) || '未知状态';
|
||||
},
|
||||
|
||||
// 获取状态标签类型
|
||||
getStatusTagType(status) {
|
||||
const fallbackMap = {
|
||||
1: 'info', // 待开始
|
||||
2: 'success', // 进行中
|
||||
3: 'warning', // 已结束
|
||||
4: 'error', // 已取消
|
||||
};
|
||||
return getDictTagType(this.assessmentScheduleStatus, status, fallbackMap);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f5f6fa;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
background: linear-gradient(135deg, #007aff, #0051d9);
|
||||
padding: calc(var(--status-bar-height) + 16px) 16px 16px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
.content-wrapper {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
display: block;
|
||||
.empty-container {
|
||||
padding: 100rpx 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
.schedule-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.notice-text {
|
||||
color: #666666;
|
||||
font-size: 14px;
|
||||
.schedule-card {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.schedule-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
min-height: 200px;
|
||||
.schedule-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
display: block;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.schedule-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.academic-info {
|
||||
font-size: 26rpx;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.schedule-description {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.description-text {
|
||||
font-size: 28rpx;
|
||||
color: #606266;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.time-info {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.time-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
|
||||
.time-label {
|
||||
font-size: 26rpx;
|
||||
color: #909399;
|
||||
min-width: 140rpx;
|
||||
}
|
||||
|
||||
.time-value {
|
||||
font-size: 26rpx;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.plan-info {
|
||||
padding-top: 8rpx;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.plan-name {
|
||||
font-size: 26rpx;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 20rpx;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16rpx 20rpx;
|
||||
border-radius: 12rpx;
|
||||
min-width: 120rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-size: 24rpx;
|
||||
margin-top: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-btn .btn-text {
|
||||
color: #3c9cff;
|
||||
}
|
||||
|
||||
.success-btn .btn-text {
|
||||
color: #5ac725;
|
||||
}
|
||||
|
||||
.warning-btn .btn-text {
|
||||
color: #ff9900;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
</style>
|
||||
@@ -114,3 +114,11 @@ export function getApplicationStatistics(positionId) {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取学生申请状态列表
|
||||
export function getStudentApplicationStatusList() {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication/student/applicationStatus',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -447,3 +447,13 @@ export function getCurrentStudentInfo(): AxiosPromise<any> {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生已申请岗位状态列表
|
||||
*/
|
||||
export function getStudentApplicationStatusList(): AxiosPromise<any[]> {
|
||||
return request({
|
||||
url: '/jcbt/workStudyApplication/student/applicationStatus',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -244,6 +244,16 @@ export function resumePosition(id: string | number) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启岗位招录
|
||||
*/
|
||||
export function startRecruiting(id: string | number) {
|
||||
return request({
|
||||
url: `/jcbt/workStudyPosition/startRecruiting/${id}`,
|
||||
method: 'put'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消岗位
|
||||
*/
|
||||
|
||||
@@ -112,12 +112,27 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="160" align="center" fixed="right">
|
||||
<el-table-column label="申请状态" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getApplicationStatusType(row)" size="small">
|
||||
{{ getApplicationStatusText(row) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="180" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" icon="View" size="small" @click="handleViewDetail(row)" title="查看详情"> 查看 </el-button>
|
||||
<el-button type="success" icon="Plus" size="small" @click="handleApply(row)" :disabled="!canApply(row)" title="申请岗位">
|
||||
申请
|
||||
<el-button
|
||||
:type="getApplyButtonType(row)"
|
||||
:icon="getApplyButtonIcon(row)"
|
||||
size="small"
|
||||
@click="handleApply(row)"
|
||||
:disabled="!canApply(row)"
|
||||
:title="getApplyButtonTitle(row)"
|
||||
>
|
||||
{{ getApplyButtonText(row) }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -141,7 +156,8 @@
|
||||
|
||||
<!-- 岗位详情对话框 -->
|
||||
<el-dialog v-model="detailDialogVisible" title="岗位详情" width="80%" :close-on-click-modal="false" class="position-detail-dialog">
|
||||
<PositionDetail v-if="detailDialogVisible && selectedPositionId" :position-id="selectedPositionId" @apply="handleApplyFromDetail" />
|
||||
<!-- <PositionDetail v-if="detailDialogVisible && selectedPositionId" :position-id="selectedPositionId" @apply="handleApplyFromDetail" /> -->
|
||||
<div style="padding: 20px; text-align: center;">岗位详情页面开发中...</div>
|
||||
<template #footer>
|
||||
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
@@ -149,12 +165,17 @@
|
||||
|
||||
<!-- 申请表单对话框 -->
|
||||
<el-dialog v-model="applyDialogVisible" title="申请岗位" width="70%" :close-on-click-modal="false" class="apply-dialog">
|
||||
<ApplicationForm
|
||||
<!-- <ApplicationForm
|
||||
v-if="applyDialogVisible && selectedPosition"
|
||||
:position="selectedPosition"
|
||||
@success="handleApplySuccess"
|
||||
@cancel="applyDialogVisible = false"
|
||||
/>
|
||||
/> -->
|
||||
<div style="padding: 20px; text-align: center;">申请表单页面开发中...</div>
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleApplySuccess">确认申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -162,10 +183,14 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { listVisiblePositions } from '@/api/jcbt/workStudyPosition';
|
||||
import type { WorkStudyPositionVO } from '@/api/jcbt/workStudyPosition';
|
||||
import PositionDetail from './detail.vue';
|
||||
import ApplicationForm from './form.vue';
|
||||
import { getStudentApplicationStatusList } from '@/api/jcbt/workStudyApplication';
|
||||
// import PositionDetail from './detail.vue';
|
||||
// import ApplicationForm from './form.vue';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 组件引用
|
||||
const queryFormRef = ref();
|
||||
@@ -179,6 +204,7 @@ const detailDialogVisible = ref(false);
|
||||
const applyDialogVisible = ref(false);
|
||||
const selectedPositionId = ref<number>();
|
||||
const selectedPosition = ref<WorkStudyPositionVO>();
|
||||
const studentApplications = ref<any[]>([]);
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
@@ -210,6 +236,13 @@ const getStatusType = (status: string) => {
|
||||
|
||||
/** 判断是否可以申请 */
|
||||
const canApply = (position: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === position.id);
|
||||
|
||||
// 如果已录用,禁用按钮
|
||||
if (application && application.status === 'approved') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查岗位状态
|
||||
if (!['PUBLISHED', 'RECRUITING'].includes(position.status || '')) {
|
||||
return false;
|
||||
@@ -282,6 +315,20 @@ const handleViewDetail = (position: WorkStudyPositionVO) => {
|
||||
|
||||
/** 申请岗位 */
|
||||
const handleApply = (position: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === position.id);
|
||||
|
||||
// 如果已有申请且状态为已提交或审核中,跳转到申请管理页面
|
||||
if (application && ['submitted', 'college_reviewing', 'final_reviewing'].includes(application.status)) {
|
||||
router.push('/jcbt/workstudy/my-applications');
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果已录用,不允许操作
|
||||
if (application && application.status === 'approved') {
|
||||
ElMessage.info('您已被该岗位录用');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canApply(position)) {
|
||||
ElMessage.warning('该岗位当前不可申请');
|
||||
return;
|
||||
@@ -298,17 +345,150 @@ const handleApplyFromDetail = (position: WorkStudyPositionVO) => {
|
||||
applyDialogVisible.value = true;
|
||||
};
|
||||
|
||||
/** 加载学生申请状态列表 */
|
||||
const loadStudentApplications = async () => {
|
||||
try {
|
||||
const response = await getStudentApplicationStatusList();
|
||||
if (response.code === 200) {
|
||||
studentApplications.value = response.data || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取申请状态失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取申请状态文本 */
|
||||
const getApplicationStatusText = (row: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === row.id);
|
||||
if (!application) return '未申请';
|
||||
|
||||
switch (application.status) {
|
||||
case 'submitted':
|
||||
return '已提交';
|
||||
case 'college_reviewing':
|
||||
return '学院审核中';
|
||||
case 'final_reviewing':
|
||||
return '学生处审核中';
|
||||
case 'approved':
|
||||
return '审核通过';
|
||||
case 'rejected':
|
||||
return '审核不通过';
|
||||
default:
|
||||
return '未知状态';
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取申请状态标签类型 */
|
||||
const getApplicationStatusType = (row: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === row.id);
|
||||
if (!application) return 'info';
|
||||
|
||||
switch (application.status) {
|
||||
case 'submitted':
|
||||
return 'primary';
|
||||
case 'college_reviewing':
|
||||
case 'final_reviewing':
|
||||
return 'warning';
|
||||
case 'approved':
|
||||
return 'success';
|
||||
case 'rejected':
|
||||
return 'danger';
|
||||
default:
|
||||
return 'info';
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取申请按钮文本 */
|
||||
const getApplyButtonText = (row: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === row.id);
|
||||
if (!application) return '申请';
|
||||
|
||||
switch (application.status) {
|
||||
case 'submitted':
|
||||
case 'college_reviewing':
|
||||
case 'final_reviewing':
|
||||
return '查看申请';
|
||||
case 'approved':
|
||||
return '已录用';
|
||||
case 'rejected':
|
||||
return '重新申请';
|
||||
default:
|
||||
return '申请';
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取申请按钮类型 */
|
||||
const getApplyButtonType = (row: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === row.id);
|
||||
if (!application) return 'success';
|
||||
|
||||
switch (application.status) {
|
||||
case 'submitted':
|
||||
case 'college_reviewing':
|
||||
case 'final_reviewing':
|
||||
return 'primary';
|
||||
case 'approved':
|
||||
return 'info';
|
||||
case 'rejected':
|
||||
return 'warning';
|
||||
default:
|
||||
return 'success';
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取申请按钮图标 */
|
||||
const getApplyButtonIcon = (row: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === row.id);
|
||||
if (!application) return 'Plus';
|
||||
|
||||
switch (application.status) {
|
||||
case 'submitted':
|
||||
case 'college_reviewing':
|
||||
case 'final_reviewing':
|
||||
return 'View';
|
||||
case 'approved':
|
||||
return 'Check';
|
||||
case 'rejected':
|
||||
return 'RefreshRight';
|
||||
default:
|
||||
return 'Plus';
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取申请按钮提示文本 */
|
||||
const getApplyButtonTitle = (row: WorkStudyPositionVO) => {
|
||||
const application = studentApplications.value.find((app) => app.positionId === row.id);
|
||||
if (!application) return '申请岗位';
|
||||
|
||||
switch (application.status) {
|
||||
case 'submitted':
|
||||
return '查看申请详情';
|
||||
case 'college_reviewing':
|
||||
return '学院审核中,查看申请详情';
|
||||
case 'final_reviewing':
|
||||
return '学生处审核中,查看申请详情';
|
||||
case 'approved':
|
||||
return '已被录用';
|
||||
case 'rejected':
|
||||
return '重新申请该岗位';
|
||||
default:
|
||||
return '申请岗位';
|
||||
}
|
||||
};
|
||||
|
||||
/** 申请成功回调 */
|
||||
const handleApplySuccess = () => {
|
||||
applyDialogVisible.value = false;
|
||||
ElMessage.success('申请提交成功!');
|
||||
// 刷新列表
|
||||
// 刷新列表和申请状态
|
||||
getPositionList();
|
||||
loadStudentApplications();
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
getPositionList();
|
||||
loadStudentApplications();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -228,6 +228,13 @@
|
||||
>
|
||||
<el-icon><Upload /></el-icon>发布岗位
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="hasPermission('jcbt:workStudyPosition:startRecruiting')"
|
||||
command="startRecruiting"
|
||||
:disabled="getRowStatus(scope.row) !== 'PUBLISHED'"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>开启招录
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="hasPermission('jcbt:workStudyPosition:suspend')"
|
||||
command="suspend"
|
||||
@@ -288,6 +295,7 @@ import {
|
||||
exportWorkStudyPosition,
|
||||
getPositionStatistics,
|
||||
publishPosition,
|
||||
startRecruiting,
|
||||
suspendPosition,
|
||||
resumePosition,
|
||||
cancelPosition
|
||||
@@ -518,6 +526,12 @@ async function handleCommand(command, row) {
|
||||
proxy?.$modal.msgSuccess('发布成功');
|
||||
operationSuccess = true;
|
||||
break;
|
||||
case 'startRecruiting':
|
||||
await proxy?.$modal.confirm('确认开启此岗位的招录?开启后学生可以申请此岗位。');
|
||||
await startRecruiting(row.id);
|
||||
proxy?.$modal.msgSuccess('开启招录成功');
|
||||
operationSuccess = true;
|
||||
break;
|
||||
case 'suspend':
|
||||
await proxy?.$modal.confirm('确认暂停此岗位的招录?暂停后学生无法申请此岗位。');
|
||||
await suspendPosition(row.id);
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
<el-table-column label="学生信息" min-width="180" align="left">
|
||||
<template #default="scope">
|
||||
<div class="student-info">
|
||||
<div class=":liststudent-info">
|
||||
<div class="student-name">{{ scope.row.studentName }}</div>
|
||||
<div class="student-number">学号:{{ scope.row.studentNumber }}</div>
|
||||
<!-- <div class="student-class">班级:{{ scope.row.className }}</div> -->
|
||||
|
||||
Reference in new issue
Block a user