This commit is contained in:
TimSpan 2024-09-04 14:02:49 +08:00
commit f06a136ea7
80 changed files with 3114 additions and 166 deletions

View File

@ -68,7 +68,6 @@ export const staticRouter: RouteRecordRaw[] =
}, },
component: () => import('@/views/login.vue') component: () => import('@/views/login.vue')
}, },
{ {
path: '/register-index', path: '/register-index',

View File

@ -60,6 +60,10 @@ public class MessageException extends RuntimeException {
this.message = resultCode.getMessage(); this.message = resultCode.getMessage();
} }
public MessageException() {
}
@Override @Override
public String toString() { public String toString() {
return StrUtil.format("业务错误:错误代码:{},错误内容:{}", Objects.isNull(this.code) ? 500 : this.code, this.message); return StrUtil.format("业务错误:错误代码:{},错误内容:{}", Objects.isNull(this.code) ? 500 : this.code, this.message);

View File

@ -1,5 +1,6 @@
package com.changhu.common.pojo.vo; package com.changhu.common.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
/** /**
@ -9,7 +10,10 @@ import lombok.Data;
*/ */
@Data @Data
public class TokenInfo { public class TokenInfo {
@Schema(description = "token的名字")
private String name; private String name;
@Schema(description = "token的值")
private String value; private String value;
public TokenInfo(String name, String value) { public TokenInfo(String name, String value) {

View File

@ -23,9 +23,6 @@ public class WebConfig implements WebMvcConfigurer {
private final List<String> whiteList = new ArrayList<>(); private final List<String> whiteList = new ArrayList<>();
public WebConfig() { public WebConfig() {
//todo 要删除的
whiteList.add("/managementSuperUser/**");
whiteList.add("/common/**"); whiteList.add("/common/**");
whiteList.add("/test/**"); whiteList.add("/test/**");
whiteList.add("/login"); whiteList.add("/login");

View File

@ -1,6 +1,8 @@
package com.changhu.enums; package com.changhu.enums;
import com.changhu.enums.handler.AbstractLoginHandler; import com.changhu.enums.handler.AbstractLoginHandler;
import com.changhu.enums.handler.ManagementPoliceUnitLogin;
import com.changhu.enums.handler.ManagementSecurityUnitLogin;
import com.changhu.enums.handler.ManagementSuperLogin; import com.changhu.enums.handler.ManagementSuperLogin;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@ -13,13 +15,12 @@ import lombok.Getter;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum ClientType { public enum ClientType {
MANAGEMENT_SUPER("management_super", "超级后台", ManagementSuperLogin.instance), MANAGEMENT_SUPER("超级后台", ManagementSuperLogin.instance),
MANAGEMENT_POLICE("management_police", "公安后台", ManagementSuperLogin.instance), MANAGEMENT_POLICE("公安后台", ManagementPoliceUnitLogin.instance),
MANAGEMENT_SECURITY("management_security", "保安后台", ManagementSuperLogin.instance), MANAGEMENT_SECURITY("保安后台", ManagementSecurityUnitLogin.instance),
MINI_PROGRAM("mini_program", "微信小程序", ManagementSuperLogin.instance), MINI_PROGRAM("微信小程序", ManagementSuperLogin.instance),
; ;
private final String value;
private final String remark; private final String remark;
private final AbstractLoginHandler loginHandler; private final AbstractLoginHandler loginHandler;
} }

View File

@ -0,0 +1,78 @@
package com.changhu.enums.handler;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSONObject;
import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.enums.ResultCode;
import com.changhu.common.exception.MessageException;
import com.changhu.common.pojo.vo.TokenInfo;
import com.changhu.common.utils.RsaUtil;
import com.changhu.common.utils.UserUtil;
import com.changhu.common.utils.ValidatorUtil;
import com.changhu.module.management.pojo.entity.ManagementPoliceUnitUser;
import com.changhu.module.management.pojo.entity.PoliceUnit;
import com.changhu.module.management.service.ManagementPoliceUnitUserService;
import com.changhu.module.management.service.PoliceUnitService;
import com.changhu.pojo.params.ManagementPoliceUnitLoginParams;
import com.changhu.support.mybatisplus.pojo.entity.BaseEntity;
/**
* @author 20252
* @createTime 2024/9/2 下午4:52
* @desc ManagementPoliceUnitLogin...
*/
public class ManagementPoliceUnitLogin extends AbstractLoginHandler {
private final ManagementPoliceUnitUserService policeUnitUserService = SpringUtil.getBean(ManagementPoliceUnitUserService.class);
private final PoliceUnitService policeUnitService = SpringUtil.getBean(PoliceUnitService.class);
public static final ManagementPoliceUnitLogin instance = new ManagementPoliceUnitLogin();
private ManagementPoliceUnitLogin() {
}
@Override
public TokenInfo login(JSONObject jsonObject) {
ManagementPoliceUnitLoginParams managementPoliceUnitLoginParams = jsonObject.to(ManagementPoliceUnitLoginParams.class);
ValidatorUtil.manual(managementPoliceUnitLoginParams);
String accountOrTelephone = managementPoliceUnitLoginParams.getAccountOrTelephone();
String password = RsaUtil.decrypt(managementPoliceUnitLoginParams.getPassword());
//查看 账号/手机号 是否存在
ManagementPoliceUnitUser managementPoliceUnitUser = policeUnitUserService.lambdaQuery()
.eq(ManagementPoliceUnitUser::getAccount, accountOrTelephone)
.or()
.eq(ManagementPoliceUnitUser::getTelephone, accountOrTelephone)
.oneOpt()
.orElseThrow(() -> new MessageException(ResultCode.USER_NOT_FOUND));
//判断用户是否禁用
if (managementPoliceUnitUser.getIsEnable().equals(IsEnable.FALSE)) {
throw new MessageException(ResultCode.USER_IS_DISABLE);
}
//判断单位是否禁用
IsEnable unitEnable = policeUnitService.lambdaQuery()
.eq(BaseEntity::getSnowFlakeId, managementPoliceUnitUser.getPoliceUnitId())
.oneOpt()
.map(PoliceUnit::getIsEnable)
.orElseThrow(() -> new MessageException("单位不存在"));
if (unitEnable.equals(IsEnable.FALSE)) {
throw new MessageException("单位被禁用");
}
//判断密码是否正确
if (!UserUtil.verifyPassWord(password, managementPoliceUnitUser.getSalt(), managementPoliceUnitUser.getPassword())) {
throw new MessageException(ResultCode.PASSWORD_ERROR);
}
//登录
SaTokenInfo saTokenInfo = UserUtil.loginAndTokenInfo(managementPoliceUnitUser.getSnowFlakeId());
//返回token
return new TokenInfo(saTokenInfo.getTokenName(), saTokenInfo.getTokenValue());
}
}

View File

@ -0,0 +1,77 @@
package com.changhu.enums.handler;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSONObject;
import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.enums.ResultCode;
import com.changhu.common.exception.MessageException;
import com.changhu.common.pojo.vo.TokenInfo;
import com.changhu.common.utils.RsaUtil;
import com.changhu.common.utils.UserUtil;
import com.changhu.common.utils.ValidatorUtil;
import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser;
import com.changhu.module.management.pojo.entity.PoliceUnit;
import com.changhu.module.management.pojo.entity.SecurityUnit;
import com.changhu.module.management.service.ManagementSecurityUnitUserService;
import com.changhu.module.management.service.SecurityUnitService;
import com.changhu.pojo.params.ManagementSecurityUnitLoginParams;
import com.changhu.support.mybatisplus.pojo.entity.BaseEntity;
/**
* @author 20252
* @createTime 2024/9/2 下午5:48
* @desc ManagementSecurityUnitLogin...
*/
public class ManagementSecurityUnitLogin extends AbstractLoginHandler {
private final ManagementSecurityUnitUserService securityUnitUserService = SpringUtil.getBean(ManagementSecurityUnitUserService.class);
private final SecurityUnitService securityUnitService = SpringUtil.getBean(SecurityUnitService.class);
public static final ManagementSecurityUnitLogin instance = new ManagementSecurityUnitLogin();
private ManagementSecurityUnitLogin() {
}
@Override
public TokenInfo login(JSONObject jsonObject) {
ManagementSecurityUnitLoginParams loginParams = jsonObject.to(ManagementSecurityUnitLoginParams.class);
ValidatorUtil.manual(loginParams);
String accountOrTelephone = loginParams.getAccountOrTelephone();
String password = RsaUtil.decrypt(loginParams.getPassword());
//查看 账号/手机号 是否存在
ManagementSecurityUnitUser managementSecurityUnitUser = securityUnitUserService.lambdaQuery()
.eq(ManagementSecurityUnitUser::getAccount, accountOrTelephone)
.or()
.eq(ManagementSecurityUnitUser::getTelephone, accountOrTelephone)
.oneOpt()
.orElseThrow(() -> new MessageException(ResultCode.ERROR));
//判断用户是否禁用
if (managementSecurityUnitUser.getIsEnable().equals(IsEnable.FALSE)) {
throw new MessageException(ResultCode.USER_IS_DISABLE);
}
//判断单位是否禁用
IsEnable unitEnable = securityUnitService.lambdaQuery()
.eq(BaseEntity::getSnowFlakeId, managementSecurityUnitUser.getSecurityUnitId())
.oneOpt()
.map(SecurityUnit::getIsEnable)
.orElseThrow(() -> new MessageException("单位不存在"));
if (unitEnable.equals(IsEnable.FALSE)) {
throw new MessageException("单位被禁用");
}
//判断密码是否正确
if (!UserUtil.verifyPassWord(password, managementSecurityUnitUser.getSalt(), managementSecurityUnitUser.getPassword())) {
throw new MessageException(ResultCode.PASSWORD_ERROR);
}
//登录
SaTokenInfo saTokenInfo = UserUtil.loginAndTokenInfo(managementSecurityUnitUser.getSnowFlakeId());
//返回token
return new TokenInfo(saTokenInfo.getTokenName(), saTokenInfo.getTokenValue());
}
}

View File

@ -38,7 +38,7 @@ public class ManagementSuperLogin extends AbstractLoginHandler {
ManagementSuperUser user = managementSuperUserService.lambdaQuery() ManagementSuperUser user = managementSuperUserService.lambdaQuery()
.eq(ManagementSuperUser::getTelephone, telephone) .eq(ManagementSuperUser::getTelephone, telephone)
.oneOpt() .oneOpt()
.orElseThrow(() -> new MessageException("用户不存在")); .orElseThrow(() -> new MessageException(ResultCode.USER_NOT_FOUND));
//判断密码是否正确 //判断密码是否正确
if (!UserUtil.verifyPassWord(password, user.getSalt(), user.getPassword())) { if (!UserUtil.verifyPassWord(password, user.getSalt(), user.getPassword())) {

View File

@ -0,0 +1,52 @@
package com.changhu.module.management.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.changhu.common.annotation.JsonBody;
import com.changhu.common.pojo.vo.TreeNodeVo;
import com.changhu.common.utils.JavaClassToTsUtil;
import com.changhu.mapper.AdministrativeDivisionMapper;
import com.changhu.module.management.pojo.params.EnterprisesUnitSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.EnterprisesUnitPagerQueryParams;
import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo;
import com.changhu.module.management.service.EnterprisesUnitService;
import com.changhu.support.mybatisplus.pojo.params.PageParams;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/**
* @author 20252
* @createTime 2024/9/3 上午10:17
* @desc EnterprisesUnitController...
*/
@Tag(name = "企事业单位")
@JsonBody
@RequestMapping("/enterprisesUnit")
public class EnterprisesUnitController {
@Autowired
private EnterprisesUnitService enterprisesUnitService;
@Operation(summary = "分页查询")
@PostMapping("/pager")
public Page<EnterprisesUnitPagerVo> pager(@RequestBody @Valid PageParams<EnterprisesUnitPagerQueryParams, EnterprisesUnitPagerVo> queryParams) {
return enterprisesUnitService.pager(queryParams);
}
@Operation(summary = "新增或保存")
@PostMapping("/saveOrUpdate")
public void saveOrUpdate(@RequestBody @Valid EnterprisesUnitSaveOrUpdateParams params) {
enterprisesUnitService.saveOrUpdate(params);
}
public static void main(String[] args) {
System.out.println(JavaClassToTsUtil.parse(EnterprisesUnitSaveOrUpdateParams.class));
}
}

View File

@ -3,6 +3,7 @@ package com.changhu.module.management.controller;
import com.changhu.common.annotation.JsonBody; import com.changhu.common.annotation.JsonBody;
import com.changhu.module.management.pojo.params.IndexCheckPassParams; import com.changhu.module.management.pojo.params.IndexCheckPassParams;
import com.changhu.module.management.pojo.params.IndexCheckStatusParams; import com.changhu.module.management.pojo.params.IndexCheckStatusParams;
import com.changhu.module.management.pojo.params.IndexDisableOrEnableParams;
import com.changhu.module.management.pojo.vo.UnitCheckStatusVo; import com.changhu.module.management.pojo.vo.UnitCheckStatusVo;
import com.changhu.module.management.service.IndexService; import com.changhu.module.management.service.IndexService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -37,4 +38,10 @@ public class IndexController {
public UnitCheckStatusVo getCheckStatus(@RequestBody @Valid IndexCheckStatusParams params) { public UnitCheckStatusVo getCheckStatus(@RequestBody @Valid IndexCheckStatusParams params) {
return indexService.getCheckStatus(params); return indexService.getCheckStatus(params);
} }
@Operation(summary = "启用或禁用状态")
@PostMapping("/disableOrEnable")
public void disableOrEnable(@RequestBody @Valid IndexDisableOrEnableParams params) {
indexService.disableOrEnable(params);
}
} }

View File

@ -0,0 +1,14 @@
package com.changhu.module.management.controller;
import com.changhu.common.annotation.JsonBody;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 20252
* @createTime 2024/9/3 上午10:21
* @desc ManagementPoliceUnitUserController...
*/
@JsonBody
@RequestMapping("/managementPoliceUnitUser")
public class ManagementPoliceUnitUserController {
}

View File

@ -0,0 +1,42 @@
package com.changhu.module.management.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.changhu.common.annotation.JsonBody;
import com.changhu.module.management.pojo.params.ManagementSecurityUnitUserSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.ManagementSecurityUnitUserPagerQueryParams;
import com.changhu.module.management.pojo.vo.ManagementSecurityUnitUserPagerVo;
import com.changhu.module.management.service.ManagementSecurityUnitUserService;
import com.changhu.support.mybatisplus.pojo.params.PageParams;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 20252
* @createTime 2024/9/3 上午10:22
* @desc ManagementSecurityUnitUserController...
*/
@Tag(name = "后台-保安用户")
@JsonBody
@RequestMapping("/managementSecurityUnitUser")
public class ManagementSecurityUnitUserController {
@Autowired
private ManagementSecurityUnitUserService managementSecurityUnitUserService;
@Operation(summary = "新增或修改")
@PostMapping("/saveOrUpdate")
public void saveOrUpdate(@RequestBody @Valid ManagementSecurityUnitUserSaveOrUpdateParams saveOrUpdateParams) {
managementSecurityUnitUserService.saveOrUpdate(saveOrUpdateParams);
}
@Operation(summary = "分页查询")
@PostMapping("/pager")
public Page<ManagementSecurityUnitUserPagerVo> pager(@RequestBody PageParams<ManagementSecurityUnitUserPagerQueryParams, ManagementSecurityUnitUserPagerVo> queryParams) {
return managementSecurityUnitUserService.pager(queryParams);
}
}

View File

@ -25,4 +25,11 @@ public abstract class AbstractUnitTypeHandler {
* @return 审核状态 * @return 审核状态
*/ */
public abstract UnitCheckStatusVo getCheckStatus(String onlyCode); public abstract UnitCheckStatusVo getCheckStatus(String onlyCode);
/**
* 启用或者禁用状态
*
* @param unitId 单位id
*/
public abstract void disableOrEnable(Long unitId);
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import com.changhu.common.db.enums.CheckStatus; import com.changhu.common.db.enums.CheckStatus;
import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.db.enums.IsOrNot; import com.changhu.common.db.enums.IsOrNot;
import com.changhu.common.db.enums.Sex; import com.changhu.common.db.enums.Sex;
import com.changhu.common.enums.ResultCode; import com.changhu.common.enums.ResultCode;
@ -11,6 +12,7 @@ import com.changhu.common.exception.MessageException;
import com.changhu.common.utils.UserUtil; import com.changhu.common.utils.UserUtil;
import com.changhu.module.management.pojo.entity.ManagementPoliceUnitUser; import com.changhu.module.management.pojo.entity.ManagementPoliceUnitUser;
import com.changhu.module.management.pojo.entity.PoliceUnit; import com.changhu.module.management.pojo.entity.PoliceUnit;
import com.changhu.module.management.pojo.entity.SecurityUnit;
import com.changhu.module.management.pojo.vo.UnitCheckStatusVo; import com.changhu.module.management.pojo.vo.UnitCheckStatusVo;
import com.changhu.module.management.service.ManagementPoliceUnitUserService; import com.changhu.module.management.service.ManagementPoliceUnitUserService;
import com.changhu.module.management.service.PoliceUnitService; import com.changhu.module.management.service.PoliceUnitService;
@ -103,4 +105,25 @@ public class PoliceUnitTypeHandler extends AbstractUnitTypeHandler {
} }
return unitCheckStatusVo; return unitCheckStatusVo;
} }
@Override
public void disableOrEnable(Long unitId) {
PoliceUnit policeUnit = policeUnitService.lambdaQuery()
.eq(BaseEntity::getSnowFlakeId, unitId)
.oneOpt()
.orElseThrow(() -> new MessageException(ResultCode.DATA_NOT_FOUND));
//取反
IsEnable isEnable = switch (policeUnit.getIsEnable()) {
case TRUE -> IsEnable.FALSE;
case FALSE -> IsEnable.TRUE;
};
boolean update = policeUnitService.lambdaUpdate()
.set(PoliceUnit::getIsEnable, isEnable)
.eq(BaseEntity::getSnowFlakeId, unitId)
.update();
if (!update) {
throw new MessageException();
}
}
} }

View File

@ -105,4 +105,25 @@ public class SecurityUnitTypeHandler extends AbstractUnitTypeHandler {
return unitCheckStatusVo; return unitCheckStatusVo;
} }
@Override
public void disableOrEnable(Long unitId) {
SecurityUnit securityUnit = securityUnitService.lambdaQuery()
.eq(BaseEntity::getSnowFlakeId, unitId)
.oneOpt()
.orElseThrow(() -> new MessageException(ResultCode.DATA_NOT_FOUND));
//取反
IsEnable isEnable = switch (securityUnit.getIsEnable()) {
case TRUE -> IsEnable.FALSE;
case FALSE -> IsEnable.TRUE;
};
boolean update = securityUnitService.lambdaUpdate()
.set(SecurityUnit::getIsEnable, isEnable)
.eq(BaseEntity::getSnowFlakeId, unitId)
.update();
if (!update) {
throw new MessageException();
}
}
} }

View File

@ -0,0 +1,28 @@
package com.changhu.module.management.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.changhu.module.management.pojo.entity.EnterprisesUnit;
import com.changhu.module.management.pojo.queryParams.EnterprisesUnitPagerQueryParams;
import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* enterprises_unit (企事业单位) 固化类
* author: luozhun
* desc 由groovy脚本自动生成
*/
@Mapper
public interface EnterprisesUnitMapper extends BaseMapper<EnterprisesUnit> {
/**
* 分页查询
*
* @param page 分页参数
* @param params 查询参数
* @return 结果
*/
Page<EnterprisesUnitPagerVo> pager(@Param("page") Page<EnterprisesUnitPagerVo> page,
@Param("params") EnterprisesUnitPagerQueryParams params);
}

View File

@ -1,8 +1,14 @@
package com.changhu.module.management.mapper; package com.changhu.module.management.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser; import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser;
import com.changhu.module.management.pojo.queryParams.ManagementSecurityUnitUserPagerQueryParams;
import com.changhu.module.management.pojo.vo.ManagementSecurityUnitUserPagerVo;
import com.changhu.support.mybatisplus.annotation.DataScope;
import com.changhu.support.mybatisplus.handler.permission.management.ManagementSecurityUnitUserPagerPermissionHandler;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/** /**
* management_security_unit_user (后台-保安单位用户表) 固化类 * management_security_unit_user (后台-保安单位用户表) 固化类
@ -12,4 +18,14 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface ManagementSecurityUnitUserMapper extends BaseMapper<ManagementSecurityUnitUser> { public interface ManagementSecurityUnitUserMapper extends BaseMapper<ManagementSecurityUnitUser> {
/**
* 分页查询
*
* @param page 分页参数
* @param params 查询参数
* @return 结果
*/
@DataScope(permissionHandler = ManagementSecurityUnitUserPagerPermissionHandler.class)
Page<ManagementSecurityUnitUserPagerVo> pager(@Param("page") Page<ManagementSecurityUnitUserPagerVo> page,
@Param("params") ManagementSecurityUnitUserPagerQueryParams params);
} }

View File

@ -0,0 +1,81 @@
package com.changhu.module.management.pojo.entity;
import java.io.Serial;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler;
import com.changhu.module.management.pojo.model.ContactPersonInfo;
import com.changhu.support.mybatisplus.pojo.entity.BaseEntity;
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import lombok.EqualsAndHashCode;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* 企事业单位 实体类
* author: luozhun
* desc 由groovy脚本自动生成
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
@TableName(autoResultMap = true)
public class EnterprisesUnit extends BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 所属公安机关id
*/
private Long policeUnitId;
/**
* 名称
*/
private String name;
/**
*
*/
private String province;
/**
*
*/
private String city;
/**
* /
*/
private String districts;
/**
* 街道
*/
private String street;
/**
* 详细地址
*/
private String address;
/**
* 联系人
*/
@TableField(typeHandler = Fastjson2TypeHandler.class)
private ContactPersonInfo contactPersonInfo;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,43 @@
package com.changhu.module.management.pojo.params;
import com.changhu.module.management.pojo.model.ContactPersonInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
/**
* @author 20252
* @createTime 2024/9/3 下午4:06
* @desc EnterprisesUnitSaveOrUpdateParams...
*/
@Data
public class EnterprisesUnitSaveOrUpdateParams {
@Schema(description = "id")
private Long snowFlakeId;
@Schema(description = "公安单位id")
@NotNull(message = "公安单位不能为空")
private Long policeUnitId;
@Schema(description = "名称")
@NotBlank(message = "名称不能为空")
private String name;
@Schema(description = "行政区划编码")
@NotEmpty(message = "行政区划不能为空")
private List<String> administrativeDivisionCodes;
@Schema(description = "详细地址")
private String address;
@Schema(description = "联系人")
private ContactPersonInfo contactPersonInfo;
@Schema(description = "备注")
private String remark;
}

View File

@ -0,0 +1,22 @@
package com.changhu.module.management.pojo.params;
import com.changhu.module.management.enums.UnitOptType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author 20252
* @createTime 2024/9/3 上午9:28
* @desc IndexDisableOrEnableParams...
*/
@Data
public class IndexDisableOrEnableParams {
@Schema(description = "单位id")
@NotNull(message = "单位id不能为空")
private Long unitId;
@Schema(description = "单位类型")
@NotNull(message = "单位类型不能为空")
private UnitOptType unitOptType;
}

View File

@ -0,0 +1,45 @@
package com.changhu.module.management.pojo.params;
import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.db.enums.Sex;
import com.changhu.common.validator.annotation.IsMobile;
import com.changhu.module.management.pojo.model.ContactPersonInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
/**
* @author 20252
* @createTime 2024/9/3 上午10:26
* @desc ManagementSecurityUnitUserSaveOrUpdateParams...
*/
@Data
public class ManagementSecurityUnitUserSaveOrUpdateParams {
@Schema(description = "id")
private Long snowFlakeId;
@NotBlank(message = "名称不能为空")
@Schema(description = "名称")
private String name;
@Schema(description = "性别")
@NotNull(message = "性别不能为空")
private Sex sex;
@IsMobile
@NotBlank(message = "手机号不能为空")
private String telephone;
@NotNull(message = "启用状态不能为空")
@Schema(description = "启用状态")
private IsEnable isEnable;
@Schema(description = "备注")
private String remark;
}

View File

@ -0,0 +1,18 @@
package com.changhu.module.management.pojo.queryParams;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author 20252
* @createTime 2024/9/3 下午3:27
* @desc EnterprisesUnitPagerQueryParams...
*/
@Data
public class EnterprisesUnitPagerQueryParams {
@NotNull(message = "公安单位id不能为空")
@Schema(description = "公安单位id")
private Long policeUnitId;
}

View File

@ -0,0 +1,20 @@
package com.changhu.module.management.pojo.queryParams;
import com.changhu.common.db.enums.Sex;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @author 20252
* @createTime 2024/9/3 上午11:02
* @desc ManagementSecurityUnitUserPagerQueryParams...
*/
@Data
public class ManagementSecurityUnitUserPagerQueryParams {
@Schema(description = "名字")
private String name;
@Schema(description = "手机号")
private String telephone;
@Schema(description = "性别")
private Sex sex;
}

View File

@ -0,0 +1,54 @@
package com.changhu.module.management.pojo.vo;
import com.changhu.module.management.pojo.model.ContactPersonInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @author 20252
* @createTime 2024/9/3 下午3:22
* @desc EnterprisesUnitPagerVo...
*/
@Data
public class EnterprisesUnitPagerVo {
@Schema(description = "id")
private Long snowFlakeId;
@Schema(description = "名字")
private String name;
@Schema(description = "公安单位id")
private Long policeUnitId;
@Schema(description = "省编码")
private String province;
@Schema(description = "省名称")
private String provinceName;
@Schema(description = "市编码")
private String city;
@Schema(description = "市名称")
private String cityName;
@Schema(description = "区编码")
private String districts;
@Schema(description = "区名称")
private String districtsName;
@Schema(description = "街编码")
private String street;
@Schema(description = "街名称")
private String streetName;
@Schema(description = "地址")
private String address;
@Schema(description = "联系方式")
private ContactPersonInfo contactPersonInfo;
@Schema(description = "备注")
private String remark;
@Schema(description = "创建时间")
private String createTime;
}

View File

@ -0,0 +1,49 @@
package com.changhu.module.management.pojo.vo;
import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.db.enums.IsOrNot;
import com.changhu.common.db.enums.Sex;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author 20252
* @createTime 2024/9/3 上午10:59
* @desc ManagementSecurityUnitUserPagerVo...
*/
@Data
public class ManagementSecurityUnitUserPagerVo {
@Schema(description = "id")
private Long snowFlakeId;
@Schema(description = "名称")
private String name;
@Schema(description = "性别")
private Sex sex;
@Schema(description = "性别")
private String account;
@Schema(description = "手机号")
private String telephone;
@Schema(description = "是否启用")
private IsEnable isEnable;
@Schema(description = "是否是超管")
private IsOrNot isAdmin;
@Schema(description = "备注")
private String remark;
@Schema(description = "创建人")
private String createUserName;
@Schema(description = "创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,32 @@
package com.changhu.module.management.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.changhu.module.management.pojo.entity.EnterprisesUnit;
import com.changhu.module.management.pojo.params.EnterprisesUnitSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.EnterprisesUnitPagerQueryParams;
import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo;
import com.changhu.support.mybatisplus.pojo.params.PageParams;
/**
* enterprises_unit (企事业单位) 服务类
* author: luozhun
* desc 由groovy脚本自动生成
*/
public interface EnterprisesUnitService extends IService<EnterprisesUnit> {
/**
* 分页查询
*
* @param queryParams 查询参数
* @return 结果
*/
Page<EnterprisesUnitPagerVo> pager(PageParams<EnterprisesUnitPagerQueryParams, EnterprisesUnitPagerVo> queryParams);
/**
* 新增或保存
*
* @param params 参数
*/
void saveOrUpdate(EnterprisesUnitSaveOrUpdateParams params);
}

View File

@ -2,6 +2,7 @@ package com.changhu.module.management.service;
import com.changhu.module.management.pojo.params.IndexCheckPassParams; import com.changhu.module.management.pojo.params.IndexCheckPassParams;
import com.changhu.module.management.pojo.params.IndexCheckStatusParams; import com.changhu.module.management.pojo.params.IndexCheckStatusParams;
import com.changhu.module.management.pojo.params.IndexDisableOrEnableParams;
import com.changhu.module.management.pojo.vo.UnitCheckStatusVo; import com.changhu.module.management.pojo.vo.UnitCheckStatusVo;
/** /**
@ -25,4 +26,11 @@ public interface IndexService {
* @return 结果 * @return 结果
*/ */
UnitCheckStatusVo getCheckStatus(IndexCheckStatusParams params); UnitCheckStatusVo getCheckStatus(IndexCheckStatusParams params);
/**
* 启用或者禁用单位
*
* @param params 参数
*/
void disableOrEnable(IndexDisableOrEnableParams params);
} }

View File

@ -1,7 +1,12 @@
package com.changhu.module.management.service; package com.changhu.module.management.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser; import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser;
import com.changhu.module.management.pojo.params.ManagementSecurityUnitUserSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.ManagementSecurityUnitUserPagerQueryParams;
import com.changhu.module.management.pojo.vo.ManagementSecurityUnitUserPagerVo;
import com.changhu.support.mybatisplus.pojo.params.PageParams;
/** /**
* management_security_unit_user (后台-保安单位用户表) 服务类 * management_security_unit_user (后台-保安单位用户表) 服务类
@ -10,4 +15,18 @@ import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser;
*/ */
public interface ManagementSecurityUnitUserService extends IService<ManagementSecurityUnitUser> { public interface ManagementSecurityUnitUserService extends IService<ManagementSecurityUnitUser> {
/**
* 新增或者修改
*
* @param saveOrUpdateParams 参数
*/
void saveOrUpdate(ManagementSecurityUnitUserSaveOrUpdateParams saveOrUpdateParams);
/**
* 分页查询
*
* @param queryParams 查询参数
* @return 分页结果
*/
Page<ManagementSecurityUnitUserPagerVo> pager(PageParams<ManagementSecurityUnitUserPagerQueryParams, ManagementSecurityUnitUserPagerVo> queryParams);
} }

View File

@ -0,0 +1,54 @@
package com.changhu.module.management.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.changhu.common.exception.MessageException;
import com.changhu.module.management.mapper.EnterprisesUnitMapper;
import com.changhu.module.management.pojo.entity.EnterprisesUnit;
import com.changhu.module.management.pojo.params.EnterprisesUnitSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.EnterprisesUnitPagerQueryParams;
import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo;
import com.changhu.module.management.service.EnterprisesUnitService;
import com.changhu.support.mybatisplus.pojo.params.PageParams;
import org.springframework.stereotype.Service;
import java.util.Optional;
/**
* enterprises_unit (企事业单位) 服务实现类
* author: luozhun
* desc 由groovy脚本自动生成
*/
@Service
public class EnterprisesUnitServiceImpl extends ServiceImpl<EnterprisesUnitMapper, EnterprisesUnit> implements EnterprisesUnitService {
@Override
public Page<EnterprisesUnitPagerVo> pager(PageParams<EnterprisesUnitPagerQueryParams, EnterprisesUnitPagerVo> queryParams) {
return baseMapper.pager(queryParams.getPage(), queryParams.getParams());
}
@Override
public void saveOrUpdate(EnterprisesUnitSaveOrUpdateParams params) {
EnterprisesUnit enterprisesUnit = BeanUtil.copyProperties(params, EnterprisesUnit.class);
Optional.ofNullable(params.getAdministrativeDivisionCodes())
.ifPresent(codes -> {
if (!codes.isEmpty()) {
enterprisesUnit.setProvince(codes.get(0));
}
if (codes.size() >= 2) {
enterprisesUnit.setCity(codes.get(1));
}
if (codes.size() >= 3) {
enterprisesUnit.setDistricts(codes.get(2));
}
if (codes.size() >= 4) {
enterprisesUnit.setStreet(codes.get(3));
}
});
boolean b = this.saveOrUpdate(enterprisesUnit);
if (!b) {
throw new MessageException();
}
}
}

View File

@ -2,6 +2,7 @@ package com.changhu.module.management.service.impl;
import com.changhu.module.management.pojo.params.IndexCheckPassParams; import com.changhu.module.management.pojo.params.IndexCheckPassParams;
import com.changhu.module.management.pojo.params.IndexCheckStatusParams; import com.changhu.module.management.pojo.params.IndexCheckStatusParams;
import com.changhu.module.management.pojo.params.IndexDisableOrEnableParams;
import com.changhu.module.management.pojo.vo.UnitCheckStatusVo; import com.changhu.module.management.pojo.vo.UnitCheckStatusVo;
import com.changhu.module.management.service.IndexService; import com.changhu.module.management.service.IndexService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -26,4 +27,11 @@ public class IndexServiceImpl implements IndexService {
.getHandler() .getHandler()
.getCheckStatus(params.getOnlyCode()); .getCheckStatus(params.getOnlyCode());
} }
@Override
public void disableOrEnable(IndexDisableOrEnableParams params) {
params.getUnitOptType()
.getHandler()
.disableOrEnable(params.getUnitId());
}
} }

View File

@ -1,10 +1,23 @@
package com.changhu.module.management.service.impl; package com.changhu.module.management.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.changhu.common.exception.MessageException;
import com.changhu.common.utils.UserUtil;
import com.changhu.module.management.mapper.ManagementSecurityUnitUserMapper; import com.changhu.module.management.mapper.ManagementSecurityUnitUserMapper;
import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser; import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser;
import com.changhu.module.management.pojo.params.ManagementSecurityUnitUserSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.ManagementSecurityUnitUserPagerQueryParams;
import com.changhu.module.management.pojo.vo.ManagementSecurityUnitUserPagerVo;
import com.changhu.module.management.service.ManagementSecurityUnitUserService; import com.changhu.module.management.service.ManagementSecurityUnitUserService;
import com.changhu.support.mybatisplus.pojo.params.PageParams;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/** /**
* management_security_unit_user (后台-保安单位用户表) 服务实现类 * management_security_unit_user (后台-保安单位用户表) 服务实现类
@ -14,4 +27,39 @@ import org.springframework.stereotype.Service;
@Service @Service
public class ManagementSecurityUnitUserServiceImpl extends ServiceImpl<ManagementSecurityUnitUserMapper, ManagementSecurityUnitUser> implements ManagementSecurityUnitUserService { public class ManagementSecurityUnitUserServiceImpl extends ServiceImpl<ManagementSecurityUnitUserMapper, ManagementSecurityUnitUser> implements ManagementSecurityUnitUserService {
@Transactional(rollbackFor = Exception.class)
@Override
public void saveOrUpdate(ManagementSecurityUnitUserSaveOrUpdateParams saveOrUpdateParams) {
//查看手机号是否已存在
boolean exists = this.lambdaQuery()
.eq(ManagementSecurityUnitUser::getTelephone, saveOrUpdateParams.getTelephone())
.exists();
if (exists) {
throw new MessageException("该手机号已存在");
}
ManagementSecurityUnitUser managementSecurityUnitUser = BeanUtil.copyProperties(saveOrUpdateParams, ManagementSecurityUnitUser.class);
//新增 需要补全一些信息
if (managementSecurityUnitUser.getSnowFlakeId() == null) {
String account = RandomUtil.randomString(6);
boolean accExits = this.lambdaQuery()
.eq(ManagementSecurityUnitUser::getAccount, account)
.exists();
if (accExits) {
throw new MessageException("生成的账号已存在 请重新提交生成");
}
//生成账号
managementSecurityUnitUser.setAccount(account);
//生成密码
String passWordEncrypt = UserUtil.passWordEncrypt(UserUtil.DEFAULT_PASSWORD);
List<String> saltAndPassWord = StrUtil.split(passWordEncrypt, "$$");
managementSecurityUnitUser.setSalt(saltAndPassWord.get(0));
managementSecurityUnitUser.setPassword(saltAndPassWord.get(1));
}
this.saveOrUpdate(managementSecurityUnitUser);
}
@Override
public Page<ManagementSecurityUnitUserPagerVo> pager(PageParams<ManagementSecurityUnitUserPagerQueryParams, ManagementSecurityUnitUserPagerVo> queryParams) {
return baseMapper.pager(queryParams.getPage(), queryParams.getParams());
}
} }

View File

@ -40,10 +40,10 @@ public class SecurityUnitServiceImpl extends ServiceImpl<SecurityUnitMapper, Sec
securityUnit.setCity(codes.get(1)); securityUnit.setCity(codes.get(1));
} }
if (codes.size() >= 3) { if (codes.size() >= 3) {
securityUnit.setCity(codes.get(2)); securityUnit.setDistricts(codes.get(2));
} }
if (codes.size() >= 4) { if (codes.size() >= 4) {
securityUnit.setCity(codes.get(3)); securityUnit.setStreet(codes.get(3));
} }
}); });
this.saveOrUpdate(securityUnit); this.saveOrUpdate(securityUnit);

View File

@ -0,0 +1,19 @@
package com.changhu.pojo.params;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @author 20252
* @createTime 2024/9/2 下午4:53
* @desc ManagementPoliceUnitLoginParams...
*/
@Data
public class ManagementPoliceUnitLoginParams {
@NotBlank(message = "账号/手机号不能为空")
private String accountOrTelephone;
@NotBlank(message = "密码不能为空")
private String password;
}

View File

@ -0,0 +1,19 @@
package com.changhu.pojo.params;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @author 20252
* @createTime 2024/9/2 下午4:53
* @desc ManagementPoliceUnitLoginParams...
*/
@Data
public class ManagementSecurityUnitLoginParams {
@NotBlank(message = "账号/手机号不能为空")
private String accountOrTelephone;
@NotBlank(message = "密码不能为空")
private String password;
}

View File

@ -0,0 +1,40 @@
package com.changhu.support.mybatisplus.handler.permission.management;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.changhu.common.enums.ResultCode;
import com.changhu.common.exception.MessageException;
import com.changhu.common.utils.UserUtil;
import com.changhu.module.management.pojo.entity.ManagementSecurityUnitUser;
import com.changhu.support.mybatisplus.handler.permission.AbstractDataPermissionHandler;
import com.changhu.support.mybatisplus.pojo.entity.BaseEntity;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
/**
* @author 20252
* @createTime 2024/9/3 上午11:11
* @desc 后台安保人员分页权限
*/
public class ManagementSecurityUnitUserPagerPermissionHandler implements AbstractDataPermissionHandler {
@Override
public Expression apply(Table table, Expression where, String mappedStatementId) {
if ("msuu".equals(table.getAlias().getName())) {
return sqlFragment();
}
return null;
}
@Override
public Expression sqlFragment() {
//查出当前用户
ManagementSecurityUnitUser managementSecurityUnitUser = Db.lambdaQuery(ManagementSecurityUnitUser.class)
.select(BaseEntity::getSnowFlakeId, ManagementSecurityUnitUser::getSecurityUnitId)
.eq(BaseEntity::getSnowFlakeId, UserUtil.getUserId())
.oneOpt()
.orElseThrow(() -> new MessageException(ResultCode.USER_NOT_FOUND));
return new EqualsTo(new Column("msuu.security_unit_id"), new LongValue(managementSecurityUnitUser.getSecurityUnitId()));
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.changhu.module.management.mapper.EnterprisesUnitMapper">
<resultMap id="EnterprisesUnitPagerVoResultMap" type="com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo">
<result
column="contact_person_info"
typeHandler="com.baomidou.mybatisplus.extension.handlers.Fastjson2TypeHandler"
property="contactPersonInfo"/>
</resultMap>
<select id="pager" resultMap="EnterprisesUnitPagerVoResultMap">
select eu.*,
ad1.name as provinceName,
ad2.name as cityName,
ad3.name as districtsName,
ad4.name as streetName
from enterprises_unit eu
left join administrative_division ad1 on eu.province = ad1.code and ad1.delete_flag = 0
left join administrative_division ad2 on eu.city = ad2.code and ad2.delete_flag = 0
left join administrative_division ad3 on eu.districts = ad3.code and ad3.delete_flag = 0
left join administrative_division ad4 on eu.street = ad4.code and ad4.delete_flag = 0
where eu.delete_flag = 0
and eu.police_unit_id = #{params.policeUnitId}
order by eu.create_time desc
</select>
</mapper>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.changhu.module.management.mapper.ManagementSecurityUnitUserMapper">
<select id="pager" resultType="com.changhu.module.management.pojo.vo.ManagementSecurityUnitUserPagerVo">
select
msuu.*,
msuu2.name as 'createUserName'
from management_security_unit_user msuu
left join management_security_unit_user msuu2 on msuu.create_by = msuu2.snow_flake_id
where
msuu.delete_flag = 0
<if test="params.name!=null and params.name!=''">
and msuu.name like concat('%',#{params.name},'%')
</if>
<if test="params.telephone!=null and params.telephone!=''">
and msuu.telephone like concat('%',#{params.telephone},'%')
</if>
<if test="params.sex!=null">
and msuu.sex = #{params.sex.value}
</if>
order by msuu.create_time desc
</select>
</mapper>

View File

@ -13,19 +13,23 @@
"ant-design-vue": "^4.2.3", "ant-design-vue": "^4.2.3",
"axios": "^1.7.5", "axios": "^1.7.5",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
"lodash-es": "^4.17.21",
"pinia": "^2.2.2", "pinia": "^2.2.2",
"pinia-plugin-persistedstate": "^3.2.0", "pinia-plugin-persistedstate": "^3.2.0",
"vue-component-type-helpers": "^2.1.2",
"sass": "^1.77.8", "sass": "^1.77.8",
"vue": "^3.4.37", "vue": "^3.4.37",
"vue-router": "4", "vue-router": "4",
"vue-uuid": "^3.0.0", "vue-uuid": "^3.0.0"
"lodash-es": "^4.17.21"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash-es": "^4.17.8", "@types/lodash-es": "^4.17.8",
"@types/node": "^22.5.1", "@types/node": "^22.5.1",
"@vitejs/plugin-vue": "^5.1.2", "@vitejs/plugin-vue": "^5.1.2",
"@vitejs/plugin-vue-jsx": "^4.0.1", "@vitejs/plugin-vue-jsx": "^4.0.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.44",
"tailwindcss": "^3.4.10",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"unplugin-vue-components": "^0.27.4", "unplugin-vue-components": "^0.27.4",
"vite": "^5.4.1", "vite": "^5.4.1",

View File

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -0,0 +1,162 @@
/* 扩展ant design pro按钮组件颜色 */
$--my-antd-important: !important;
.btn-danger {
color: #ffffff;
background-color: #F5222D;
border-color: #F5222D;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #ff4d4f $--my-antd-important;
border-color: #ff4d4f $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #cf1322 $--my-antd-important;
border-color: #cf1322 $--my-antd-important;
}
}
.btn-volcano {
color: #ffffff;
background-color: #FA541C;
border-color: #FA541C;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #ff7a45 $--my-antd-important;
border-color: #ff7a45 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #d4380d $--my-antd-important;
border-color: #d4380d $--my-antd-important;
}
}
.btn-warn {
color: #ffffff;
background-color: #FAAD14;
border-color: #FAAD14;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #ffc53d $--my-antd-important;
border-color: #ffc53d $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #d48806 $--my-antd-important;
border-color: #d48806 $--my-antd-important;
}
}
.btn-success {
color: #ffffff;
background-color: #52C41A;
border-color: #52C41A;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #73d13d $--my-antd-important;
border-color: #73d13d $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #389e0d $--my-antd-important;
border-color: #389e0d $--my-antd-important;
}
}
.button-color-cyan {
color: #ffffff;
background-color: #13C2C2;
border-color: #13C2C2;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #36cfc9 $--my-antd-important;
border-color: #36cfc9 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #08979c $--my-antd-important;
border-color: #08979c $--my-antd-important;
}
}
.btn-daybreak {
color: #ffffff;
background-color: #1890FF;
border-color: #1890FF;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #096dd9 $--my-antd-important;
border-color: #096dd9 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #40a9ff $--my-antd-important;
border-color: #40a9ff $--my-antd-important;
}
}
.button-color-geekblue {
color: #ffffff;
background-color: #2F54EB;
border-color: #2F54EB;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #1d39c4 $--my-antd-important;
border-color: #1d39c4 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #597ef7 $--my-antd-important;
border-color: #597ef7 $--my-antd-important;
}
}
.btn-purple {
color: #ffffff;
background-color: #722ED1;
border-color: #722ED1;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #9254de $--my-antd-important;
border-color: #9254de $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #531dab $--my-antd-important;
border-color: #531dab $--my-antd-important;
}
}
.table-row-warn td {
background-color: #fefca6;
}
.table-row-danger td {
background-color: #f79988;
}
.table-row-success td {
background-color: #b6fcbe;
}
.ant-table-summary td {
background: #edeff6;
}

View File

@ -0,0 +1,206 @@
<template>
<a-form
ref="formProMaxRef"
v-bind="props"
:model="modelValue"
>
<a-row :gutter="props.gutter">
<a-col
v-for="(item,field) in props.formItemOptions as FormProMaxItemOptions<T>"
:key="field"
v-bind="getResponsive(item)"
>
<a-form-item
:name="field"
v-bind="item"
:label="undefined"
>
<template v-slot:label>
{{ item.label }}
<template v-if="item.remarkRender">
<a-popover :title="item.label" :content="item.remarkRender()">
<QuestionCircleOutlined class="margin-left-xs" style="color: red"/>
</a-popover>
</template>
</template>
<!-- 自定义组件 -->
<!-- ant design vue 组件 -->
<a-input
v-if="item.type==='input'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<a-input-password
v-else-if="item.type==='inputPassword'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<a-input-number
v-else-if="item.type==='inputNumber'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
/>
<a-textarea
v-else-if="item.type==='inputTextArea'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<a-radio-group
v-else-if="item.type==='radioGroup'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:options="item.options"
/>
<a-checkbox-group
v-else-if="item.type==='checkboxGroup'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:options="item.options"
/>
<a-select
v-else-if="item.type==='select'"
v-model:value="modelValue[field]"
style="width: 100%"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
:options="item.options"
/>
<a-tree-select
v-else-if="item.type==='treeSelect'"
style="width: 100%"
v-model:value="modelValue[field]"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
:tree-data="item.options"
/>
<a-cascader
v-else-if="item.type ==='cascader'"
style="width: 100%"
v-model:value="modelValue[field]"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
:options="item.options"
/>
<a-range-picker
v-else-if="item.type ==='rangePicker'"
style="width: 100%"
v-model:value="modelValue[field]"
v-bind="item.componentsProps"
:placeholder="item.componentsProps?.placeholder ?? ['开始日期', '结束日期']"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<a-date-picker
v-else-if="item.type ==='datePicker'"
style="width: 100%"
v-model:value="modelValue[field]"
v-bind="item.componentsProps"
:placeholder="item.componentsProps?.placeholder ?? '请选择日期'"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<a-time-range-picker
v-else-if="item.type ==='timeRangePicker'"
style="width: 100%"
v-model:value="modelValue[field]"
v-bind="item.componentsProps"
:placeholder="item.componentsProps?.placeholder ?? ['开始时间', '结束时间']"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<a-time-picker
v-else-if="item.type ==='timePicker'"
style="width: 100%"
v-model:value="modelValue[field]"
v-bind="item.componentsProps"
:placeholder="getPlaceholder(item)"
:allowClear="item.componentsProps?.allowClear ?? true"
/>
<template v-else-if="item.type==='custom'">
<component :is="item.customRender"/>
</template>
</a-form-item>
</a-col>
</a-row>
<slot name="formOperation"></slot>
</a-form>
</template>
<script setup lang="ts" generic="T extends Record<string,any>">
import {FormInstance} from "ant-design-vue";
import {ref} from "vue";
import {FormExpose} from "ant-design-vue/es/form/Form";
import {QuestionCircleOutlined} from '@ant-design/icons-vue'
import {FormProMaxItemOptions, FormProMaxItemProps, FormProMaxProps} from "@/types/components/form/index.ts";
const modelValue = defineModel<T>('value', {
default: {}
})
const props = withDefaults(defineProps<FormProMaxProps<T>>(), {
grid: () => {
return {
span: 24
}
},
gutter: 10,
labelCol: () => {
return {
style: {
width: '100px'
}
}
},
wrapperCol: () => {
return {
span: 18
}
},
labelAlign: "left",
colon: undefined,
disabled: undefined,
hideRequiredMark: undefined,
labelWrap: undefined,
scrollToFirstError: undefined,
validateOnRuleChange: undefined
})
const formProMaxRef = ref<FormInstance>(null!)
const getResponsive = (item: FormProMaxItemProps): Grid => {
//span
if (item.grid) return item.grid.span ? {span: item.grid.span} : {...item.grid};
return {...props.grid}
}
//: =formItem=label
const getPlaceholder = (item: FormProMaxItemProps) => item.componentsProps?.placeholder ?? item.placeholder ?? (item.type.includes('input') ? `请输入${item.label}` : `请选择${item.label}`)
defineExpose<FormExpose>({
validate: (nameList, options) => formProMaxRef.value?.validate(nameList, options),
resetFields: (name) => formProMaxRef.value?.resetFields(name),
clearValidate: () => formProMaxRef.value?.clearValidate(),
getFieldsValue: (nameList) => formProMaxRef.value?.getFieldsValue(nameList),
scrollToField: (name, options) => formProMaxRef.value?.scrollToField(name, options),
validateFields: (nameList, options) => formProMaxRef.value?.validateFields(nameList, options)
})
</script>
<style scoped>
</style>

View File

@ -0,0 +1,20 @@
<template>
<i v-if="type==='class'" :class="[`iconfont ${fontClass}`]" :style="{fontSize:`${size}px`}"/>
<svg v-else-if="type === 'svg'" :style="{width:`${size}px`,height:`${size}px`}">
<use :href="`#${fontClass}`"/>
</svg>
</template>
<script setup lang="ts">
import {IconFontProps} from "@/types/components/iconfont/IconFont";
withDefaults(defineProps<IconFontProps>(), {
size: 25,
type: "svg"
});
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,47 @@
<template>
<template v-for="item in menuList">
<a-sub-menu
v-if="item.type === 'dir'"
:key="item.path"
>
<template #icon>
<icon-font :font-class="item.icon"/>
</template>
<template #title>
<span class="margin-left-xs">{{ item.title }}</span>
</template>
<menu-item :menu-list="item.children"/>
</a-sub-menu>
<a-menu-item
v-else
:key="item.path as any"
@click="()=>router.push(item.path)"
>
<template #icon>
<icon-font :font-class="item.icon"/>
</template>
<span class="margin-left-xs">{{ item.title }}</span>
</a-menu-item>
</template>
</template>
<script setup lang="ts">
import {SystemMenu} from "@/types/config";
import {useRouter} from "vue-router";
import IconFont from "@/components/iconfont/IconFont.vue";
const router = useRouter()
withDefaults(defineProps<{
menuList?: SystemMenu[]
}>(), {
menuList: (): SystemMenu[] => {
return [];
}
})
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,30 @@
<template>
<a-menu
:selectedKeys="activeMenus"
mode="inline"
:inline-collapsed="false"
class="system-menus"
>
<menu-item :menu-list="SYSTEM_MENUS"/>
</a-menu>
</template>
<script setup lang="ts">
import {computed} from "vue";
import {useRoute} from "vue-router";
import {SYSTEM_MENUS} from "@/config";
import MenuItem from "@/components/layout/MenuItem.vue";
const route = useRoute()
const activeMenus = computed(() => [route.path]);
console.log(activeMenus)
</script>
<style scoped lang="scss">
.system-menus {
height: calc(100% - 100px);
overflow-y: auto;
}
</style>

View File

@ -12,6 +12,7 @@
<div v-else class="logo flex-center"> <div v-else class="logo flex-center">
<img src="@/assets/vue.svg" title="超级后台" alt="xx"> <img src="@/assets/vue.svg" title="超级后台" alt="xx">
</div> </div>
<SystemMenus/>
</a-layout-sider> </a-layout-sider>
<a-layout> <a-layout>
<a-layout-header <a-layout-header
@ -37,6 +38,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref} from "vue"; import {ref} from "vue";
import LayoutHeader from "@/components/layout/header/LayoutHeader.vue"; import LayoutHeader from "@/components/layout/header/LayoutHeader.vue";
import SystemMenus from "@/components/layout/SystemMenus.vue";
const collapsed = ref<boolean>(false); const collapsed = ref<boolean>(false);

View File

@ -38,17 +38,22 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {ref} from 'vue' import {onMounted, ref} from 'vue'
import {FormInstance, notification} from "ant-design-vue"; import {FormInstance, notification} from "ant-design-vue";
import {Rule} from "ant-design-vue/es/form"; import {Rule} from "ant-design-vue/es/form";
import {LoginParams} from "@/types/views/login.ts"; import {LoginParams} from "@/types/views/login.ts";
import api from "@/axios"; import api from "@/axios";
import {CLIENT_TYPE} from "@/config"; import {CLIENT_TYPE} from "@/config";
import rsaUtil from "@/utils/rsaUtil.ts";
import {TokenInfo} from "@/types/stores/userStore.ts"; import {TokenInfo} from "@/types/stores/userStore.ts";
import {useUserStore} from "@/stores/modules/userStore.ts"; import {useUserStore} from "@/stores/modules/userStore.ts";
import {useRouter} from "vue-router"; import {useRoute, useRouter} from "vue-router";
import rsaUtil from "@/utils/rsaUtil.ts";
onMounted(()=>{
const route = useRoute()
loginParams.value.telephone = <string> route.query.account
loginParams.value.password =<string> route.query.password
})
const userStore = useUserStore() const userStore = useUserStore()
const router = useRouter() const router = useRouter()
@ -56,7 +61,6 @@ const formRef = ref<FormInstance>(null!)
const loginParamsRule: Record<keyof LoginParams, Rule[]> = { const loginParamsRule: Record<keyof LoginParams, Rule[]> = {
telephone: [ telephone: [
{required: true, message: '请输入手机号', trigger: 'change'}, {required: true, message: '请输入手机号', trigger: 'change'},
{len: 11, message: "长度不够", trigger: 'blur'},
], ],
password: [ password: [
{required: true, message: '请输入密码', trigger: 'change'}, {required: true, message: '请输入密码', trigger: 'change'},
@ -64,10 +68,11 @@ const loginParamsRule: Record<keyof LoginParams, Rule[]> = {
], ],
} }
const loginParams = ref<LoginParams>({ const loginParams = ref<LoginParams>({
telephone: __APP_ENV.VITE_APP_ENV === "development" ? '15576404472' : '', telephone: __APP_ENV.VITE_APP_ENV === "development" ? '13575462314' : '',
password: __APP_ENV.VITE_APP_ENV === "development" ? '123456' : '' password: __APP_ENV.VITE_APP_ENV === "development" ? '123456' : ''
}); });
/** /**
* 登录 * 登录
*/ */
@ -78,7 +83,7 @@ const login = async () => {
const resp = await api.post<TokenInfo>('/login', { const resp = await api.post<TokenInfo>('/login', {
clientType: CLIENT_TYPE, clientType: CLIENT_TYPE,
loginParams: { loginParams: {
telephone: loginParams.value.telephone, accountOrTelephone: loginParams.value.telephone,
password: rsaUtil.encryptStr(loginParams.value.password) password: rsaUtil.encryptStr(loginParams.value.password)
} }
}) })
@ -95,6 +100,7 @@ const login = async () => {
}) })
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -0,0 +1,223 @@
<template>
<div class="table-pro-content">
<div class="card padding" v-if="props.searchFormOptions">
<FormProMax
ref="searchFormRef"
:form-item-options="props.searchFormOptions"
v-model:value="searchParams"
v-bind="props.searchFormProps"
>
<template v-slot:formOperation>
<a-space class="margin-right flex-end">
<a-button type="primary" @click="search">
<search-outlined/>
搜索
</a-button>
<a-button danger @click="resetFormAndTable">
<rollback-outlined/>
重置
</a-button>
</a-space>
</template>
</FormProMax>
</div>
<div class="card padding margin-top-xs">
<div class="flex-justify-between">
<slot name="tableHeader" :selectKeys="selectKeys" :selectRows="selectRows"></slot>
<div></div>
<slot name="tableHeaderRight" :selectKeys="selectKeys" :selectRows="selectRows"></slot>
<a-space>
<template v-if="!props.searchFormOptions">
<a-tooltip>
<template #title>刷新数据</template>
<a-button shape="circle" @click="requestGetTableData">
<ReloadOutlined/>
</a-button>
</a-tooltip>
</template>
<template v-if="props.isPrinter">
<a-tooltip>
<template #title>打印数据</template>
<a-button shape="circle">
<PrinterOutlined/>
</a-button>
</a-tooltip>
</template>
</a-space>
</div>
<a-table
class="margin-top"
v-bind="props"
:columns="tableColumns"
:row-selection="props.isSelection ? props.selectionProps ? props.selectionProps : defaultSelectProps : null"
:data-source="dataSource"
:loading="loading"
:pagination="false"
>
<template v-for="(_,key) in slots" v-slot:[key]="scope">
<slot v-if="!includes(['tableHeader','tableHeaderRight'],key)" :name="key" v-bind="scope"></slot>
</template>
</a-table>
<a-pagination
v-if="props.isPagination"
class="flex-end margin-top margin-right"
v-model:current="pageParams.current"
v-model:page-size="pageParams.size"
:total="pageParams.total"
v-bind="props.paginationProps"
@change="handleCurrentChange"
@showSizeChange="handleSizeChange"
/>
</div>
</div>
</template>
<script
setup
lang="ts"
generic="T extends BaseTableRowRecord = {},P extends { [key: string]: any } ={}"
>
import FormProMax from "@/components/form/FormProMax.vue";
import {PrinterOutlined, ReloadOutlined, RollbackOutlined, SearchOutlined} from "@ant-design/icons-vue";
import {computed, onMounted, Ref, ref} from "vue";
import {FormInstance} from "ant-design-vue";
import useTableProMax from "@/hooks/useTableProMax";
import {includes, isEmpty} from "lodash-es";
import {BaseTableRowRecord, TableProMaxProps, TableProMaxRowSelect, TableProMaxSlots} from "@/types/components/table";
const selectKeys = ref<string[]>([])
const selectRows = ref<T[]>([]) as Ref<T[]>
const defaultSelectProps: TableProMaxRowSelect<T> = {
type: "checkbox",
selectedRowKeys: selectKeys as any,
preserveSelectedRowKeys: true,
onSelect: (record, selected) => {
if (selected) {
selectKeys.value.push(record[props.rowKey] as string)
selectRows.value.push(record)
} else {
selectKeys.value.splice(selectKeys.value.findIndex(x => x === record[props.rowKey]));
selectRows.value.splice(selectRows.value.findIndex(r => r[props.rowKey] === record[props.rowKey]))
}
},
onChange: (selectedRowKeys, selectedRows) => {
selectKeys.value = selectedRowKeys as string[];
selectRows.value = selectedRows;
},
}
const clearSelect = () => {
selectKeys.value = [];
selectRows.value = [];
}
const props = withDefaults(defineProps<TableProMaxProps<T, P>>(), {
needIndex: true,
searchFormProps: () => {
return {
grid: {
xs: 24,
sm: 12,
md: 8,
lg: 6,
xl: 4
},
labelCol: undefined,
wrapperCol: undefined
}
},
rowKey: 'snowFlakeId',
requestAuto: true,
isPagination: true,
isSelection: false,
paginationProps: () => {
return {
showTotal: (total) => `${total}`,
showSizeChanger: true,
}
},
bordered: true,
showSorterTooltip: undefined,
showHeader: undefined,
expandFixed: undefined,
expandRowByClick: undefined,
defaultExpandAllRows: undefined,
showExpandColumn: undefined,
sticky: undefined
})
const slots = defineSlots<TableProMaxSlots<T>>()
const tableColumns = computed(() => {
let cols = props.columns;
if (!isEmpty(cols) && props.needIndex) {
if (!(cols?.[0].dataIndex === 'index')) {
cols?.unshift({
dataIndex: 'index',
width: 60,
title: '序号',
customRender: ({index}) => index + 1
})
}
}
return cols;
})
/**
* 表单实例
*/
const searchFormRef = ref<FormInstance>() as Ref<FormInstance>
/**
* 查询参数
*/
const searchParams = ref<P | Record<string, any>>(props.defaultSearchParams || {}) as Ref<P>
const {
loading,
dataSource,
pageParams,
search,
requestGetTableData,
handleSizeChange,
handleCurrentChange,
resetState
} = useTableProMax(props.requestApi,
searchFormRef,
searchParams,
props.isPagination,
props.dataCallback,
props.requestError
)
onMounted(() => props.requestAuto && requestGetTableData(true))
/**
* 重置表单并查询
*/
const resetFormAndTable = () => {
searchFormRef.value?.resetFields()
requestGetTableData()
}
defineExpose({
selectKeys,
selectRows,
requestGetTableData,
clearSelect,
resetTable: () => {
searchFormRef.value?.resetFields()
resetState();
}
})
</script>
<style scoped lang="scss">
.card {
box-sizing: border-box;
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.05);
}
</style>

View File

@ -0,0 +1,17 @@
import api from "@/axios";
type DictType =
'CheckStatus'
| 'DeleteFlag'
| 'IsEnable'
| 'IsOrNot'
| 'Sex'
export const initEnums = () => {
api.get<Record<DictType, SelectNodeVo<any>[]>>('/common/enums').then(resp => {
sessionStorage.setItem('dictMap', JSON.stringify(resp.data))
})
}
export const dictSelectNodes = <T>(enumType: DictType): SelectNodeVo<T>[] => JSON.parse(sessionStorage.getItem('dictMap') as string)?.[enumType] || []

View File

@ -1,2 +1,35 @@
export const CLIENT_TYPE = "MANAGEMENT_SUPER"; import {SystemMenu} from "@/types/config";
export const ROUTER_WHITE_LIST: string[] = ['/login', '/test','/enterprise']; export const ROUTER_WHITE_LIST: string[] = ['/login', '/test','/enterprise'];
export const CLIENT_TYPE:string = "MANAGEMENT_SECURITY";
export const SYSTEM_MENUS: SystemMenu[] = [
{
title: '首页',
name: 'index',
path: '/index',
type: "menu",
component: () => import('@/views/index.vue')
}, {
title: '用户管理',
name: 'userManagement',
path: '/userManagement',
type: 'dir',
children: [
{
title: '后台管理',
name: 'bgManagement',
path: '/bgManagement',
type: 'menu',
component: () => import('@/views/userManagement/bgManagement/index.vue')
}, {
title: '小程序管理',
name: 'uniManagement',
path: '/uniManagement',
type: 'menu',
component: () => import('@/views/userManagement/uniManagement/index.vue')
}
]
}
]

View File

@ -61,3 +61,19 @@ interface BaseEnum<T> {
value: T; value: T;
label: string label: string
} }
interface dataStatus {
account: string;
password: string;
remark: string;
checkStatus: {
extData: {
color: string;
};
label: string;
value: number;
};
}

View File

@ -0,0 +1,134 @@
import {ref, Ref} from "vue";
import {Page, PageParams, PageResult} from "@/types/hooks/useTableProMax.ts";
import {FormInstance} from "ant-design-vue";
import {BaseTableRowRecord, RequestApiType} from "@/types/components/table";
/**
*
* @param api
* @param searchFormRef
* @param searchParams
* @param isPageTable
* @param dataCallBack
* @param requestError
*/
export default <T extends BaseTableRowRecord, P extends Record<string, any> | PageParams<P>>(api: RequestApiType<T, P>,
searchFormRef: Ref<FormInstance>,
searchParams: Ref<P>,
isPageTable: boolean = true,
dataCallBack?: (data: T[]) => T[],
requestError?: (errorMsg: any) => void) => {
const dataSource = ref<T[]>([]) as Ref<T[]>;
const loading = ref<boolean>(false);
const pageParams = ref<Page>({
current: 1,
size: 10,
total: 0
})
/**
*
*/
const requestGetTableData = async (isInit: boolean = false) => {
try {
//校验表单
!isInit && await searchFormRef.value?.validate();
//组装参数
let totalSearchParams;
if (isPageTable) {
totalSearchParams = {
params: searchParams.value,
page: {
current: pageParams.value.current,
size: pageParams.value.size
}
} as PageParams<P>;
} else {
totalSearchParams = searchParams.value
}
loading.value = true;
const resp = await api(totalSearchParams as P);
let tableData: T[];
if (isPageTable) {
const {current, records, size, total} = resp.data as PageResult<T>;
isPageTable && updatePageParams({
current: parseInt(current),
size: parseInt(size),
total: parseInt(total)
});
tableData = records;
} else {
tableData = resp.data as T[]
}
dataCallBack && (tableData = dataCallBack(tableData));
dataSource.value = tableData;
} catch (error) {
requestError && requestError(error);
} finally {
loading.value = false;
}
}
/**
*
*/
const updatePageParams = (ps: Page) => Object.assign(pageParams.value, ps)
/**
* dataSource loading pageParams
*/
const resetState = () => {
dataSource.value = [];
loading.value = false;
pageParams.value = {
current: 1,
size: 10,
total: 0
}
}
/**
* requestGetTableData 1
* requestGetTableData
*/
const search = async () => {
pageParams.value.current = 1;
await requestGetTableData();
};
/**
* @description
* @param _
* @param {Number} size
*/
const handleSizeChange = async (_: number, size: number) => {
pageParams.value.current = 1;
pageParams.value.size = size;
await requestGetTableData();
};
/**
* @description
* @param current
*/
const handleCurrentChange = async (current: number) => {
pageParams.value.current = current;
await requestGetTableData();
};
return {
dataSource,
loading,
pageParams,
requestGetTableData,
search,
handleSizeChange,
handleCurrentChange,
resetState
};
}

View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,18 +1,22 @@
import {createApp} from 'vue' import {createApp} from 'vue'
import App from '@/App.vue' import App from '@/App.vue'
import '@/reset.css' import '@/reset.css'
import './index.css'
// 公共样式 // 公共样式
import '@/assets/scss/common.scss' import '@/assets/scss/common.scss'
import '@/assets/scss/myAntD.scss'
// iconfont css // iconfont css
import "@/assets/iconfont/iconfont.css"; import "@/assets/iconfont/iconfont.css";
// vue Router // vue Router
import router from "@/router"; import router from "@/router";
// pinia stores // pinia stores
import pinia from "@/stores"; import pinia from "@/stores";
import {initEnums} from "@/config/dict.ts";
initEnums()
const vueApp = createApp(App); const vueApp = createApp(App);
vueApp vueApp
.use(router) .use(router)
.use(pinia) .use(pinia)

View File

@ -32,7 +32,7 @@ router.beforeEach(async (to, from, next) => {
// 不在白名单内需要查看是否携带token 没有token需要返回登录页进行登录 // 不在白名单内需要查看是否携带token 没有token需要返回登录页进行登录
if (!userStore.getTokenInfo?.value) { if (!userStore.getTokenInfo?.value) {
await message.warn('未找到token请重新登陆!') await message.warn('未找到token请重新登陆!')
return next('/login'); return next('/enterprise');
} }
//放行 //放行
return next(); return next();

View File

@ -1,14 +1,35 @@
import {RouteRecordRaw} from "vue-router"; import {RouteRecordRaw} from "vue-router";
import {SYSTEM_MENUS} from "@/config";
import {SystemMenu} from "@/types/config";
/**
*
*/
const extractMenuToRouter = (): RouteRecordRaw[] => {
const result: RouteRecordRaw[] = []
const traverse = (data: SystemMenu[]) => {
data.forEach(item => {
if (item.type === 'dir' && item.children && item.children.length > 0) {
traverse(item.children)
} else {
result.push({
path: item.path,
name: item.name,
meta: {
title: item.title
},
component: item.component
} as RouteRecordRaw)
}
})
}
traverse(SYSTEM_MENUS)
return result;
}
export const staticRouter: RouteRecordRaw[] = [ export const staticRouter: RouteRecordRaw[] = [
{
path: '/enterprise',
name: 'enterprise',
meta: {
title: '企业入驻',
},
component: () => import("@/views/enterprise.vue"),
},
{ {
path: '/login', path: '/login',
name: 'login', name: 'login',
@ -19,30 +40,20 @@ export const staticRouter: RouteRecordRaw[] = [
}, { }, {
path: "/", path: "/",
redirect: '/index', redirect: '/index',
}, {
path: '/test',
name: 'test',
meta: {
title: '测试',
},
component: () => import("@/views/test.vue"),
}, { }, {
path: '/layout', path: '/layout',
name: 'layout', name: 'layout',
redirect: '/index', redirect: '/index',
component: () => import("@/components/layout/layout.vue"), component: () => import("@/components/layout/layout.vue"),
children: [ children: extractMenuToRouter()
}, {
path: '/test',
name: 'test',
component: () => import("@/views/test.vue"),
},
{ {
path: '/index', path: '/enterprise',
name: 'index', name: 'enterprise',
meta: { component: () => import("@/views/enterprise.vue"),
title: '首页',
icon: 'icon-shouye',
fixed: true,
isKeepAlive: false
},
component: () => import('@/views/index.vue')
}
]
}, },
] ]

View File

@ -5,7 +5,7 @@ export const useUserStore = defineStore({
id: 'useUserStore', id: 'useUserStore',
state: (): UserStore => { state: (): UserStore => {
return { return {
tokenInfo: undefined tokenInfo: undefined,
} }
}, },
actions: { actions: {
@ -14,7 +14,7 @@ export const useUserStore = defineStore({
}, },
async resetUserInfo() { async resetUserInfo() {
this.tokenInfo = undefined; this.tokenInfo = undefined;
} },
}, },
getters: { getters: {
getTokenInfo: (state): TokenInfo => state.tokenInfo as TokenInfo, getTokenInfo: (state): TokenInfo => state.tokenInfo as TokenInfo,

View File

@ -0,0 +1,73 @@
import {
FormProps,
RangePicker,
Input,
InputNumber,
Textarea,
InputPassword,
RadioGroup,
Select,
TreeSelect,
Cascader,
CheckboxGroup,
DatePicker,
FormItem, TimeRangePicker, TimePicker,
} from "ant-design-vue";
import {Ref, UnwrapRef, VNode} from "vue";
import {ComponentProps} from "vue-component-type-helpers";
type FormProMaxItemType =
| 'custom'
| 'input'
| 'inputPassword'
| 'inputNumber'
| 'inputTextArea'
| 'radioGroup'
| 'select'
| 'selectIcon'
| 'selectUser'
| 'treeSelect'
| 'cascader'
| 'checkboxGroup'
| 'datePicker'
| 'rangePicker'
| 'timeRangePicker'
| 'timePicker';
interface FormProMaxItemCommonProps extends ComponentProps<typeof FormItem> {
label?: string,
grid?: Grid,
placeholder?: string,
remarkRender?: () => VNode | string,
customRender?: () => VNode;
options?: (SelectNodeVo<unknown> | TreeNodeVo<unknown>) [] | Ref<(SelectNodeVo<unknown> | TreeNodeVo<unknown>)[]>
}
export interface FormProMaxItemProps<T extends FormProMaxItemType = any, C = any> extends FormProMaxItemCommonProps {
type: T
componentsProps?: C
}
export type FormProMaxItemOptions<T> = {
[key in keyof T | string]:
FormProMaxItemProps<'custom', ComponentProps<Record<string, any>>>
| FormProMaxItemProps<'input', ComponentProps<typeof Input>>
| FormProMaxItemProps<'inputPassword', ComponentProps<typeof InputPassword>>
| FormProMaxItemProps<'inputNumber', ComponentProps<typeof InputNumber>>
| FormProMaxItemProps<'inputTextArea', ComponentProps<typeof Textarea>>
| FormProMaxItemProps<'radioGroup', ComponentProps<typeof RadioGroup>>
| FormProMaxItemProps<'select', ComponentProps<typeof Select>>
| FormProMaxItemProps<'treeSelect', ComponentProps<typeof TreeSelect>>
| FormProMaxItemProps<'cascader', ComponentProps<typeof Cascader>>
| FormProMaxItemProps<'checkboxGroup', ComponentProps<typeof CheckboxGroup>>
| FormProMaxItemProps<'datePicker', ComponentProps<typeof DatePicker>>
| FormProMaxItemProps<'rangePicker', ComponentProps<typeof RangePicker>>
| FormProMaxItemProps<'timeRangePicker', ComponentProps<typeof TimeRangePicker>>
| FormProMaxItemProps<'timePicker', ComponentProps<typeof TimePicker>>
}
export interface FormProMaxProps<T = {}> extends FormProps {
grid?: Grid
gutter?: number;
formItemOptions?: FormProMaxItemOptions<T> | Ref<FormProMaxItemOptions<T>> | UnwrapRef<FormProMaxItemOptions<T>>
}

View File

@ -0,0 +1,5 @@
export interface IconFontProps {
fontClass?: string,
size?: number,
type?: 'class' | 'svg'
}

View File

@ -0,0 +1,55 @@
import {PaginationProps, Table, TableProps} from "ant-design-vue";
import {TableRowSelection} from "ant-design-vue/lib/table/interface";
import {Ref, UnwrapRef} from "vue";
import {ColumnType} from "ant-design-vue/es/table/interface";
import {ComponentSlots} from "vue-component-type-helpers";
import {FormProMaxItemOptions, FormProMaxProps} from "@/types/components/form";
import {PageParams, PageResult} from "@/types/hooks/useTableProMax.ts";
export type TableProMaxColumnType<T extends BaseTableRowRecord> = Omit<ColumnType<T>, 'dataIndex'> & {
dataIndex: keyof T | string | string[] | number | number[];
}
export type TableProMaxProps<
T extends BaseTableRowRecord = {},
P extends { [key: string]: any } = {}
> = Partial<Omit<TableProps<T>, "dataSource" | 'pagination' | 'loading' | 'rowKey' | 'columns'>> & {
rowKey?: keyof T,
columns?: TableProMaxColumnType<T>[],
searchFormProps?: Omit<FormProMaxProps<P>, 'formItems'>
searchFormOptions?: FormProMaxItemOptions<P> | Ref<FormProMaxItemOptions<P>> | UnwrapRef<FormProMaxItemOptions<P>>,
defaultSearchParams?: { [key in keyof P | string]: any };
requestAuto?: boolean,
requestApi: RequestApiType<T, P>,
requestError?: (errorMsg: any) => void,
dataCallback?: (data: T[]) => T[],
isPagination?: boolean,
paginationProps?: TableProMaxPaginationProps,
isSelection?: boolean,
selectionProps?: TableProMaxRowSelect<T>,
isPrinter?: boolean,
needIndex?: boolean
}
export type TableProMaxSlots<T> = ComponentSlots<typeof Table> & {
tableHeader: (scope: { selectKeys: string[], selectRows: T[] }) => any,
tableHeaderRight: (scope: { selectKeys: string[], selectRows: T[] }) => any,
}
export type RequestApiType<T extends BaseTableRowRecord, P extends {
[key: string]: any
} = {}> = (params: P | PageParams<P>) => Promise<JsonResult<T[] | PageResult<T>>>;
export type TableProMaxPaginationProps = Partial<Omit<PaginationProps, "current" | "pageSize" | "total">>;
export type TableProMaxRowSelect<T extends BaseTableRowRecord> = TableRowSelection<T>;
export interface BaseTableRowRecord {
snowFlakeId?: string;
createUserName?: string;
createTime?: Date | string;
updateUserName?: string;
updateTime?: Date | string
}

View File

@ -0,0 +1,12 @@
import {RouteComponent} from "vue-router";
export interface SystemMenu {
type: 'dir' | 'menu';
title: string;
path: string;
name: string;
icon?: string;
component?: RouteComponent;
children?: SystemMenu[];
}

View File

@ -0,0 +1,26 @@
/**
*
*/
export interface Page {
current: number,
size: number,
total: number
}
/**
*
*/
export interface PageParams<T extends Record<string, any> = {}> {
params: T & { [key: string]: any },
page: Omit<Page, 'total'>
}
/**
*
*/
export interface PageResult<T> {
current: string,
records: T[],
size: string,
total: string
}

View File

@ -1,8 +1,10 @@
export interface TokenInfo { export interface TokenInfo {
name: string; name: string;
value: string; value: string;
} }
export interface UserStore { export interface UserStore {
tokenInfo?: TokenInfo; tokenInfo?: TokenInfo;
} }

View File

@ -0,0 +1,22 @@
import {BaseTableRowRecord} from "@/types/components/table";
export interface BgManagementPagerQueryParams extends BaseTableRowRecord{
/** 名称 **/
name?: string;
/** 社会编码 **/
socialCode?: string;
/** 行政区划编码 **/
administrativeDivisionCodes?: string[];
/** 是否启用 **/
isEnable?: number;
/** 审核状态 **/
checkStatus?: number;
/** 账号 **/
account?:string,
sex?:BaseEnum<number>,
telephone?:string,
createTime?:string,
snowFlakeId?:string,
remark?:string,
}

View File

@ -1,7 +1,12 @@
<template> <template>
<div class="enterprise"> <!-- 背景色覆盖整个页面并且能够正常滚动内容同时固定内层内容的位置 -->
<div class="enterpriseIndex"> <body style="margin: 0; padding: 0; overflow: auto">
<div class="enterpriseItem"> <!-- 背景色层 -->
<div class="bg-gray-100" style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: -1"></div>
<!-- 内容层 -->
<div class="flex justify-center" style="position: relative; margin: 20px auto">
<!-- 卡片盒子 -->
<div class="w-full max-w-3xl p-6 bg-white rounded-xl shadow-md">
<a-tabs v-model:activeKey="activeKey" :tabBarGutter="300" centered > <a-tabs v-model:activeKey="activeKey" :tabBarGutter="300" centered >
<a-tab-pane key="1" tab="企业入驻"> <a-tab-pane key="1" tab="企业入驻">
<a-form <a-form
@ -14,13 +19,13 @@
@finish="onFinish" @finish="onFinish"
> >
<a-form-item label="名称" name="name"> <a-form-item label="名称" name="name">
<a-input v-model:value="formDate.name" /> <a-input :allowClear="true" v-model:value="formDate.name" />
</a-form-item> </a-form-item>
<a-form-item label="统一社会编码" name="socialCode"> <a-form-item :allowClear="true" label="统一社会编码" name="socialCode">
<a-input v-model:value="formDate.socialCode"/> <a-input v-model:value="formDate.socialCode"/>
</a-form-item> </a-form-item>
<a-form-item label="公司性质" name="nature"> <a-form-item label="公司性质" name="nature">
<a-input v-model:value="formDate.nature"/> <a-input :allowClear="true" v-model:value="formDate.nature"/>
</a-form-item> </a-form-item>
<a-form-item label="行政区划" > <a-form-item label="行政区划" >
<a-cascader v-model:value="formDate.administrativeDivisionCodes" :show-search="{ filter }" :options="administrativeDivisionTree" @change="searchAdministrativeDivisionTree" /> <a-cascader v-model:value="formDate.administrativeDivisionCodes" :show-search="{ filter }" :options="administrativeDivisionTree" @change="searchAdministrativeDivisionTree" />
@ -28,43 +33,58 @@
<a-form-item label="营业执照" name="businessLicense"> <a-form-item label="营业执照" name="businessLicense">
<SingleImageFileUpload v-model:value="formDate.businessLicense"></SingleImageFileUpload> <SingleImageFileUpload v-model:value="formDate.businessLicense"></SingleImageFileUpload>
</a-form-item> </a-form-item>
<a-form-item label="法人名"> <a-form-item label="法人名">
<a-input v-model:value="formDate.legalPersonInfo" /> <a-input :allowClear="true" v-model:value="formDate.legalPersonInfo" />
</a-form-item> </a-form-item>
<a-form-item label="法人手机号码"> <a-form-item label="法人手机号码">
<a-input v-model:value="formDate.telephone" /> <a-input :allowClear="true" v-model:value="formDate.telephone" />
</a-form-item> </a-form-item>
<a-form-item label="详细地址" > <a-form-item label="详细地址" >
<a-input v-model:value="formDate.address" /> <a-input :allowClear="true" v-model:value="formDate.address" />
</a-form-item> </a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }"> <a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button type="primary" html-type="submit" style="width: 100px">确认</a-button> <a-button type="primary" html-type="submit" style="width: 100px">确认</a-button>
<a-button style="width: 100px;margin-left: 10px" @click="resetForm">重置表单</a-button>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="2" tab="查询企业状态" > <a-tab-pane key="2" tab="查询企业状态" >
<a-form
</a-tab-pane> :label-col="labelCol"
</a-tabs> :wrapper-col="wrapperCol"
</div> :model="statusDate"
layout="horizontal">
<a-form-item label="统一社会编码" name="onlyCode" :rules="[{ required: true, message: '请输入统一社会编码进行查询' }]">
<a-input :allowClear="true" v-model:value="statusDate.onlyCode"></a-input>
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button type="primary" html-type="submit" style="width: 100px" @click="getCheckStatus">确认</a-button>
</a-form-item>
</a-form>
</a-tab-pane></a-tabs>
</div> </div>
</div> </div>
</body>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ref, onMounted} from 'vue'; import {ref, onMounted,createVNode,h} from 'vue';
import type { Rule } from 'ant-design-vue/es/form'; import type { Rule } from 'ant-design-vue/es/form';
import type { ShowSearchType } from 'ant-design-vue/es/cascader'; import type { ShowSearchType } from 'ant-design-vue/es/cascader';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import api from "@/axios"; import api from "@/axios";
import { message } from 'ant-design-vue'; import {message, Modal} from 'ant-design-vue';
import SingleImageFileUpload from "@/components/upload/SingleImageFileUpload.vue"; import SingleImageFileUpload from "@/components/upload/SingleImageFileUpload.vue";
import {useRouter} from "vue-router";
const activeKey = ref('1'); const activeKey = ref('1');
const labelCol = { style: { width: '120px' } }; const labelCol = { style: { width: '120px' } };
const wrapperCol = { span: 14 }; const wrapperCol = { span: 14 };
const administrativeDivisionTree = ref<TreeNodeVo<string>[]>([]) const administrativeDivisionTree = ref<TreeNodeVo<string>[]>([])
const formDateRef = ref(); const formDateRef = ref();
const router = useRouter()
interface formDatePort { interface formDatePort {
name:string, name:string,
socialCode:string, socialCode:string,
@ -76,6 +96,11 @@ interface formDatePort {
nature:string nature:string
} }
interface statusPort {
onlyCode:string,
unitOptType:string
}
const formDate = ref<formDatePort>({ const formDate = ref<formDatePort>({
name:'', name:'',
socialCode:'', socialCode:'',
@ -87,6 +112,10 @@ const formDate = ref<formDatePort>({
nature:'' nature:''
}) })
const statusDate = ref<statusPort>({
onlyCode:'',
unitOptType:'SECURITY_UNIT'
})
const rules: Record<string, Rule[]> = { const rules: Record<string, Rule[]> = {
name: [ name: [
{ required: true, message: '请输入姓名', trigger: 'change' }, { required: true, message: '请输入姓名', trigger: 'change' },
@ -105,9 +134,6 @@ const rules: Record<string, Rule[]> = {
] ]
}; };
// 1 // 1
const DivisionTree = async ()=>{ const DivisionTree = async ()=>{
const resp = await api.get<TreeNodeVo<string>[]>('/common/administrativeDivisionTree') const resp = await api.get<TreeNodeVo<string>[]>('/common/administrativeDivisionTree')
@ -116,6 +142,7 @@ const DivisionTree = async ()=>{
// 2 // 2
const filter: ShowSearchType['filter'] = (inputValue, path) => { const filter: ShowSearchType['filter'] = (inputValue, path) => {
console.log(inputValue,path)
return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1); return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
}; };
@ -123,8 +150,6 @@ const filter: ShowSearchType['filter'] = (inputValue, path) => {
const searchAdministrativeDivisionTree = (e:Array<string>)=>{ const searchAdministrativeDivisionTree = (e:Array<string>)=>{
formDate.value.administrativeDivisionCodes = e formDate.value.administrativeDivisionCodes = e
} }
// //
const onFinish = async ()=>{ const onFinish = async ()=>{
// //
@ -143,9 +168,7 @@ const onFinish = async ()=>{
address:formDate.value.address address:formDate.value.address
} }
const resp = await api.post('/common/securityUnitRegister',securityUnitRegisterParams) const resp = await api.post('/common/securityUnitRegister',securityUnitRegisterParams)
console.log(resp) message.success(resp.message)
await message.loading('正在注册中...')
message.success('企业入驻成功')
await formDateRef.value.resetFields() // await formDateRef.value.resetFields() //
formDate.value = { formDate.value = {
name:'', name:'',
@ -157,26 +180,56 @@ const onFinish = async ()=>{
address:'', address:'',
nature:'' nature:''
} }
} }
//
const resetForm = ()=>{
formDateRef.value.resetFields()
}
//
const getCheckStatus = async ()=>{
const indexCheckStatusParams = {
onlyCode:statusDate.value.onlyCode,
unitOptType:statusDate.value.unitOptType
}
const resp = await api.post<dataStatus>('/management/getCheckStatus',indexCheckStatusParams)
showConfirm(resp.data)
}
const showConfirm = (columnsDate:dataStatus) => {
if(columnsDate.checkStatus.value === 0){
Modal.success({
title: `审核通过`,
icon: createVNode(ExclamationCircleOutlined),
content: h('div', {}, [
h('div', `账号:${columnsDate.account}`),
h('div', `密码:${columnsDate.password}`),
h('div', `${columnsDate.remark}`)
]),
okText:'跳转',
async onOk() {
await router.push({
path:'/login',
query:{
account:columnsDate.account,
password:columnsDate.password
}
}).then(()=>{})
},
onCancel() {},
});
}else{
Modal.error({
title: `未审核`,
icon: createVNode(ExclamationCircleOutlined),
content:`${columnsDate.remark}`,
});
}
};
onMounted( async ()=>{ onMounted( async ()=>{
await DivisionTree() await DivisionTree()
}) })
</script> </script>
<style scoped lang="scss">
.enterprise{
display: flex;
justify-content: center; /* 水平居中 */
align-items: center;
text-align: center;
height: 100vh;
width: 100%;
.enterpriseIndex{
border: 1px solid #cccccc;
height: 90vh;
width: 800px;
}
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
index页面 <div> index页面</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@ -0,0 +1,12 @@
<template>
<div>服务项目管理</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -1,13 +1,264 @@
<template> <template>
<div> <div>
<SingleImageFileUpload v-model:value="url"></SingleImageFileUpload> <TableProMax
</div> ref="tableRef"
:request-api="reqApi"
:columns="columns"
:searchFormOptions="searchFormOptions"
:scroll="{x}"
>
<template #tableHeader>
<a-space>
<a-button type="primary" @click="addUserManagement">新增用户</a-button>
</a-space>
</template> </template>
<script setup lang="ts"> </TableProMax>
import SingleImageFileUpload from "@/components/upload/SingleImageFileUpload.vue"; <a-modal
v-model:open="visible"
:title="title"
@ok="submit"
@cancel="closeModal"
>
<FormProMax ref="formRef" v-model:value="formParams" :form-item-options="formItemOptions"/>
</a-modal>
</div>
</template>
<script setup lang="tsx">
import TableProMax from "@/components/table/TableProMax.vue";
import {TableProMaxProps} from "@/types/components/table";
import api from "@/axios";
import {ref} from "vue"; import {ref} from "vue";
const url = ref<string>('') import {ComponentExposed} from "vue-component-type-helpers";
import {dictSelectNodes} from "@/config/dict.ts";
import {BgManagementPagerQueryParams} from "@/types/views/bgManagement.ts";
import FormProMax from "@/components/form/FormProMax.vue";
import {FormProMaxItemOptions} from "@/types/components/form";
import {FormExpose} from "ant-design-vue/es/form/Form";
import {message} from "ant-design-vue";
import {} from '@/hooks/useTableProMax.ts'
type TableProps = TableProMaxProps<BgManagementPagerQueryParams>
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
// table
const reqApi: TableProps['requestApi'] = (params) => api.post('/managementSecurityUnitUser/pager', params) //
const columns: TableProps['columns'] = [
{
dataIndex: 'account',
title: '账号',
width: 100,
ellipsis: true
},
{
dataIndex: 'name',
title: '名称',
width: 200,
ellipsis: true
}, {
dataIndex: 'sex',
title: '性别',
customRender: ({text}) => <a-tag>{text?.label}</a-tag>,
width: 150
}, {
dataIndex: 'telephone',
title: '手机号码',
width: 150,
ellipsis: true
},
{
dataIndex: 'createTime',
title: '创建时间',
width: 200,
ellipsis: true,
},
{
dataIndex: 'snowFlakeId',
title: '社区唯一编码',
width: 200,
ellipsis: true
}, {
dataIndex: 'remark',
title: '备注',
width: 200,
ellipsis: true
}, {
dataIndex: 'isEnable',
title: '是否启用',
customRender: ({text}) => <a-tag color={text?.extData?.color}>{text?.label}</a-tag>,
width: 150
}, {
dataIndex: 'opt',
title: '操作',
fixed: "right",
customRender({record}) {
return <a-space>
<a-button class={record.isEnable.value === 0 ? 'btn-danger' : 'btn-success'} onClick={async () => {
const resp = await api.post('/management/disableOrEnable', {
unitId: record.snowFlakeId,
unitOptType: UNIT_TYPE.security
})
message.success(resp.message)
await tableRef.value?.requestGetTableData()
}}>
{record.isEnable.value === 0 ? '禁用' : '启用'}
</a-button>
<a-button>
删除
</a-button>
<a-button onClick={async () => {
visible.value = true
title.value = "编辑用户"
formParams.value.snowFlakeId = record.snowFlakeId
formParams.value.name = record.name,
formParams.value.sex = record.sex.value,
formParams.value. telephone = record.telephone,
formParams.value.isEnable = record.isEnable?.value,
formParams.value.remark = record.remark
}}>
编辑
</a-button>
</a-space>
}
},
]
const x: number = columns.reduce((a, b) => a + (b.width as number), 0)
const searchFormOptions: TableProps["searchFormOptions"] = {
name: {
type: 'input',
label: '名称'
}, sex: {
type: 'select',
label: '性别',
options: [
{
value: null,
label: '全部'
}, ...dictSelectNodes('Sex')
]
},
telephone: {
type: 'input',
label: '手机号'
},
isEnable: {
type: 'select',
label: '是否启用',
options: [
{
value: null,
label: '全部'
}, ...dictSelectNodes('IsEnable')
]
}
}
const visible = ref(false)
const title = ref('新增用户')
const formRef = ref<FormExpose>(null)
const formParams = ref<{
snowFlakeId?: string,
name: string,
sex: number,
telephone: string,
isEnable: boolean,
remark?: string,
}>({
name: '',
sex: null,
telephone: '',
isEnable: null,
})
interface FromItem {
snowFlakeId?: string,
name: string,
sex: number,
telephone: string,
isEnable: boolean,
remark?: string,
}
const formItemOptions = ref<FormProMaxItemOptions<FromItem>>({
name:{
type:'input',
label:'姓名',
required:true,
},
sex:{
type:'radioGroup',
label:'性别',
options: dictSelectNodes('Sex'),
required:true,
},
telephone:{
type:'input',
label:'手机号',
required:true,
},
isEnable:{
type:'radioGroup',
label:'启用状态',
options: dictSelectNodes('IsEnable'),
required:true,
},
remark:{
type:'inputTextArea',
label:'备注',
}
})
const submit = async () => {
await formRef.value.validate()
const snowFlakeId = ref('')
if(title.value === '新增用户'){
snowFlakeId.value = ''
}else{
snowFlakeId.value = formParams.value.snowFlakeId
}
const managementSecurityUnitUserSaveOrUpdateParams = {
snowFlakeId:snowFlakeId.value,
name:formParams.value.name,
sex:formParams.value.sex,
telephone:formParams.value.telephone,
isEnable:formParams.value.isEnable,
remark:formParams.value.remark
}
const resp = await api.post('/managementSecurityUnitUser/saveOrUpdate',managementSecurityUnitUserSaveOrUpdateParams)
message.success(resp.message)
close()
}
const close = ()=>{
tableRef.value?.requestGetTableData()
visible.value = false
closeModal()
}
const closeModal = () => {
formParams.value = {
name:'',
sex:null,
telephone:'',
isEnable:null,
remark:''
}
visible.value = false
// formRef.value.
console.log('取消')
}
//Form
const addUserManagement = () => {
visible.value = true
title.value = ''
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
</style> </style>

View File

@ -0,0 +1,12 @@
<template>
<div>用户管理</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,11 @@
<template>
<div>小程序管理</div>
</template>
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,9 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
}

View File

@ -0,0 +1,162 @@
/* 扩展ant design pro按钮组件颜色 */
$--my-antd-important: !important;
.btn-danger {
color: #ffffff;
background-color: #F5222D;
border-color: #F5222D;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #ff4d4f $--my-antd-important;
border-color: #ff4d4f $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #cf1322 $--my-antd-important;
border-color: #cf1322 $--my-antd-important;
}
}
.btn-volcano {
color: #ffffff;
background-color: #FA541C;
border-color: #FA541C;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #ff7a45 $--my-antd-important;
border-color: #ff7a45 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #d4380d $--my-antd-important;
border-color: #d4380d $--my-antd-important;
}
}
.btn-warn {
color: #ffffff;
background-color: #FAAD14;
border-color: #FAAD14;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #ffc53d $--my-antd-important;
border-color: #ffc53d $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #d48806 $--my-antd-important;
border-color: #d48806 $--my-antd-important;
}
}
.btn-success {
color: #ffffff;
background-color: #52C41A;
border-color: #52C41A;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #73d13d $--my-antd-important;
border-color: #73d13d $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #389e0d $--my-antd-important;
border-color: #389e0d $--my-antd-important;
}
}
.button-color-cyan {
color: #ffffff;
background-color: #13C2C2;
border-color: #13C2C2;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #36cfc9 $--my-antd-important;
border-color: #36cfc9 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #08979c $--my-antd-important;
border-color: #08979c $--my-antd-important;
}
}
.btn-daybreak {
color: #ffffff;
background-color: #1890FF;
border-color: #1890FF;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #096dd9 $--my-antd-important;
border-color: #096dd9 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #40a9ff $--my-antd-important;
border-color: #40a9ff $--my-antd-important;
}
}
.button-color-geekblue {
color: #ffffff;
background-color: #2F54EB;
border-color: #2F54EB;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #1d39c4 $--my-antd-important;
border-color: #1d39c4 $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #597ef7 $--my-antd-important;
border-color: #597ef7 $--my-antd-important;
}
}
.btn-purple {
color: #ffffff;
background-color: #722ED1;
border-color: #722ED1;
&:hover, &:focus {
color: #ffffff $--my-antd-important;
background-color: #9254de $--my-antd-important;
border-color: #9254de $--my-antd-important;
}
&:active, &.active {
color: #ffffff $--my-antd-important;
background-color: #531dab $--my-antd-important;
border-color: #531dab $--my-antd-important;
}
}
.table-row-warn td {
background-color: #fefca6;
}
.table-row-danger td {
background-color: #f79988;
}
.table-row-success td {
background-color: #b6fcbe;
}
.ant-table-summary td {
background: #edeff6;
}

View File

@ -0,0 +1,54 @@
import {h, Ref, ref, VNode} from "vue";
import {Modal} from "ant-design-vue";
import {FormExpose} from "ant-design-vue/es/form/Form";
import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
import FormProMax from "@/components/form/FormProMax.vue";
import {FormProMaxItemOptions, FormProMaxProps} from "@/types/components/form";
export function submitSimpleFormModal<T>(props: {
title: string,
formParams?: T & Record<string, any>,
formProps?: Omit<FormProMaxProps<T>, 'formItemOptions'>,
formOptions: FormProMaxItemOptions<T>
submit: (params: T) => Promise<any>,
cancel?: (params: T) => Promise<any>,
icon?: () => VNode,
maskClosable?: boolean,
width?: string | number
}) {
if (!props.formParams) props.formParams = {} as T
if (!props.width) props.width = 520
const formRef = ref<FormExpose>(null)
const _formParams = ref<T>({
...props.formParams
}) as Ref<T>
Modal.confirm({
icon: props.icon ? props.icon() : ' ',
width: props.width,
maskClosable: props.maskClosable ?? true,
title: props.title,
content: () => <FormProMax
ref={formRef}
v-model={[_formParams.value, 'value']}
{...props.formProps}
formItemOptions={props.formOptions}
/>,
onOk: async () => {
await formRef.value?.validate()
await props.submit(_formParams.value);
},
onCancel: async () => props.cancel && await props.cancel(_formParams.value)
})
}
export const deleteDataModal = (name: string, submit: () => Promise<any>, cancel?: () => Promise<any>) => {
Modal.confirm({
title: `确认删除【${name}】吗?`,
icon: h(ExclamationCircleOutlined),
content: h('div', {style: 'color:red;'}, '此操作将删除数据,且无法找回!'),
onOk: async () => await submit(),
onCancel: async () => cancel && await cancel()
});
}

View File

@ -7,11 +7,11 @@ type DictType =
| 'IsOrNot' | 'IsOrNot'
| 'Sex' | 'Sex'
export const initEnums = () => { export const initDict = () => {
api.get<Record<DictType, SelectNodeVo<any>[]>>('/common/enums').then(resp => { api.get<Record<DictType, SelectNodeVo<any>[]>>('/common/enums').then(resp => {
sessionStorage.setItem('dictMap', JSON.stringify(resp.data)) sessionStorage.setItem('dictMap', JSON.stringify(resp.data))
}) })
} }
export const enumSelectNodes = <T>(enumType: DictType): SelectNodeVo<T>[] => JSON.parse(sessionStorage.getItem('dictMap') as string)?.[enumType] || [] export const dictSelectNodes = <T>(dictType: DictType): SelectNodeVo<T>[] => JSON.parse(sessionStorage.getItem('dictMap') as string)?.[dictType] || []

View File

@ -2,6 +2,10 @@ import {SystemMenu} from "@/types/config";
export const CLIENT_TYPE = "MANAGEMENT_SUPER"; export const CLIENT_TYPE = "MANAGEMENT_SUPER";
export const ROUTER_WHITE_LIST: string[] = ['/login', '/test']; export const ROUTER_WHITE_LIST: string[] = ['/login', '/test'];
export const UNIT_TYPE = {
security: 'SECURITY_UNIT',
police: 'POLICE_UNIT'
}
export const SYSTEM_MENUS: SystemMenu[] = [ export const SYSTEM_MENUS: SystemMenu[] = [
{ {

View File

@ -0,0 +1,36 @@
import {onMounted, reactive, toRefs} from "vue";
import api from "@/axios";
interface SelectAndTreeNodeType {
administrativeDivisionTree: TreeNodeVo<string>[];
}
export const callbackResult: { [key in keyof SelectAndTreeNodeType]: (params?: Record<string, any>) => Promise<SelectAndTreeNodeType[key]> } = {
administrativeDivisionTree: async (params = {level: 4}) => (await api.get<TreeNodeVo<string>[]>('/common/administrativeDivisionTree', params)).data,
}
export default (type?: keyof SelectAndTreeNodeType | (keyof SelectAndTreeNodeType)[], params?: { [key in keyof SelectAndTreeNodeType]?: Record<string, any> }) => {
const allData = reactive<SelectAndTreeNodeType>({
administrativeDivisionTree: [],
})
const refreshData = (type: keyof SelectAndTreeNodeType | (keyof SelectAndTreeNodeType)[]) => {
if (typeof type === "string") {
//@ts-ignore
callbackResult[type](params?.[type]).then(data => allData[type] = data)
} else {
//@ts-ignore
type.forEach(t => callbackResult[t](params?.[t]).then(data => allData[t] = data))
}
}
onMounted(() => type && refreshData(type))
return {
refreshData,
...toRefs(allData),
callbackResult
}
}

View File

@ -4,15 +4,17 @@ import '@/reset.css'
// 公共样式 // 公共样式
import '@/assets/scss/common.scss' import '@/assets/scss/common.scss'
//ant design 扩展样式
import '@/assets/scss/myAntD.scss'
// iconfont css // iconfont css
import "@/assets/iconfont/iconfont.css"; import "@/assets/iconfont/iconfont.css";
// vue Router // vue Router
import router from "@/router"; import router from "@/router";
// pinia stores // pinia stores
import pinia from "@/stores"; import pinia from "@/stores";
import {initEnums} from "@/config/dict.ts"; import {initDict} from "@/config/dict.ts";
initEnums(); initDict();
const vueApp = createApp(App); const vueApp = createApp(App);

View File

@ -46,3 +46,60 @@ export interface PoliceUnitPagerVo extends BaseTableRowRecord {
/** 审核状态 **/ /** 审核状态 **/
checkStatus?: BaseEnum<number>; checkStatus?: BaseEnum<number>;
} }
export interface EnterprisesUnitPagerQueryParams {
/** 公安单位id **/
policeUnitId: string;
}
export interface EnterprisesUnitPagerVo extends BaseTableRowRecord {
/** 名字 **/
name?: string;
/** 公安单位id **/
policeUnitId: string;
/** 省编码 **/
province?: string;
/** 省名称 **/
provinceName?: string;
/** 市编码 **/
city?: string;
/** 市名称 **/
cityName?: string;
/** 区编码 **/
districts?: string;
/** 区名称 **/
districtsName?: string;
/** 街编码 **/
street?: string;
/** 街名称 **/
streetName?: string;
/** 地址 **/
address?: string;
/** 联系方式 **/
contactPersonInfo?: {
name: string;
telephone: string;
};
/** 备注 **/
remark?: string;
}
export interface EnterprisesUnitSaveOrUpdateParams {
/** id **/
snowFlakeId?: string;
/** 公安单位id **/
policeUnitId: string;
/** 名称 **/
name: string;
/** 行政区划编码 **/
administrativeDivisionCodes: string[];
/** 详细地址 **/
address?: string;
/** 联系人 **/
contactPersonInfo?: {
name: string;
telephone: string;
};
/** 备注 **/
remark?: string;
}

View File

@ -13,14 +13,24 @@
import TableProMax from "@/components/table/TableProMax.vue"; import TableProMax from "@/components/table/TableProMax.vue";
import {ref} from "vue"; import {ref} from "vue";
import {ComponentExposed} from "vue-component-type-helpers"; import {ComponentExposed} from "vue-component-type-helpers";
import {TableProMaxProps} from "@/types/components/table"; import {TableProMaxProps, TableProMaxSlots} from "@/types/components/table";
import {PoliceUnitPagerQueryParams, PoliceUnitPagerVo} from "@/types/views/unitManage/policeUnit.ts"; import {
EnterprisesUnitPagerQueryParams, EnterprisesUnitPagerVo, EnterprisesUnitSaveOrUpdateParams,
PoliceUnitPagerQueryParams,
PoliceUnitPagerVo
} from "@/types/views/unitManage/policeUnit.ts";
import api from "@/axios"; import api from "@/axios";
import {enumSelectNodes} from "@/config/dict.ts"; import {dictSelectNodes} from "@/config/dict.ts";
import {message} from "ant-design-vue"; import {message, Modal} from "ant-design-vue";
import {UNIT_TYPE} from "@/config";
import {PageParams} from "@/types/hooks/useTableProMax.ts";
import {submitSimpleFormModal} from "@/components/tsx/ModalPro.tsx";
import useSelectAndTreeNodeVos from "@/hooks/useSelectAndTreeNodeVos.ts";
type TableProps = TableProMaxProps<PoliceUnitPagerVo, PoliceUnitPagerQueryParams> type TableProps = TableProMaxProps<PoliceUnitPagerVo, PoliceUnitPagerQueryParams>
const {administrativeDivisionTree} = useSelectAndTreeNodeVos('administrativeDivisionTree')
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!) const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
const reqApi: TableProps['requestApi'] = (params) => api.post('/policeUnit/pager', params) const reqApi: TableProps['requestApi'] = (params) => api.post('/policeUnit/pager', params)
const columns: TableProps['columns'] = [ const columns: TableProps['columns'] = [
@ -55,13 +65,14 @@ const columns: TableProps['columns'] = [
dataIndex: 'opt', dataIndex: 'opt',
title: '操作', title: '操作',
customRender({record}) { customRender({record}) {
if (record.checkStatus.value === 1) {
return <a-space> return <a-space>
{record.checkStatus.value === 1 && <a-popconfirm <a-popconfirm
title="确认审核通过嘛?" title="确认审核通过嘛?"
onConfirm={async () => { onConfirm={async () => {
const resp = await api.post('/management/checkPass', { const resp = await api.post('/management/checkPass', {
checkDataId: record.snowFlakeId, checkDataId: record.snowFlakeId,
unitOptType: 'POLICE_UNIT' unitOptType: UNIT_TYPE.police
}) })
message.success(resp.message) message.success(resp.message)
await tableRef.value?.requestGetTableData() await tableRef.value?.requestGetTableData()
@ -69,8 +80,25 @@ const columns: TableProps['columns'] = [
<a-button type="primary">审核通过 <a-button type="primary">审核通过
</a-button> </a-button>
</a-popconfirm> </a-popconfirm>
</a-space>
} }
{record.isEnable.value === 0 ? <a-button danger>禁用</a-button> : <a-button></a-button>} return <a-space>
<a-button
class="btn-success"
onClick={() => showEnterprisesUnit(record)}
>企事业单位
</a-button>
<a-button
class={record.isEnable.value === 0 ? 'btn-danger' : 'btn-success'}
onClick={async () => {
const resp = await api.post('/management/disableOrEnable', {
unitId: record.snowFlakeId,
unitOptType: UNIT_TYPE.police
})
message.success(resp.message)
await tableRef.value?.requestGetTableData()
}}
>{record.isEnable.value === 0 ? '禁用' : '启用'}</a-button>
</a-space> </a-space>
}, },
} }
@ -89,7 +117,7 @@ const searchFormOptions: TableProps["searchFormOptions"] = {
{ {
value: null, value: null,
label: '全部' label: '全部'
}, ...enumSelectNodes('IsEnable') }, ...dictSelectNodes('IsEnable')
] ]
}, checkStatus: { }, checkStatus: {
type: 'select', type: 'select',
@ -98,11 +126,140 @@ const searchFormOptions: TableProps["searchFormOptions"] = {
{ {
value: null, value: null,
label: '全部' label: '全部'
}, ...enumSelectNodes('CheckStatus') }, ...dictSelectNodes('CheckStatus')
] ]
} }
} }
type _TableProps = TableProMaxProps<EnterprisesUnitPagerVo, EnterprisesUnitPagerQueryParams>;
const showEnterprisesUnit = (policeUnitPagerVo: PoliceUnitPagerVo) => {
const saveOrUpdateEnterprisesUnit = (data?: EnterprisesUnitSaveOrUpdateParams & {
contactPersonInfoName?: string;
contactPersonInfoTelephone?: string
}) => {
submitSimpleFormModal<EnterprisesUnitSaveOrUpdateParams & {
contactPersonInfoName?: string;
contactPersonInfoTelephone?: string
}>({
title: data.snowFlakeId ? `${data.name}】 信息编辑` : '新增企事业单位',
formOptions: {
name: {
type: 'input',
label: '单位名称',
required: true
},
administrativeDivisionCodes: {
type: 'cascader',
label: '行政区划',
required: true,
options: administrativeDivisionTree.value,
componentsProps: {
showSearch: true
}
},
address: {
type: 'inputTextArea',
label: '详细地址'
},
contactPersonInfoName: {
type: 'input',
label: '联系人名称'
},
contactPersonInfoTelephone: {
type: 'input',
label: '联系人电话'
},
remark: {
type: 'inputTextArea',
label: '备注'
}
},
formParams: data,
submit: async (params) => {
params.contactPersonInfo = {
name: params.contactPersonInfoName,
telephone: params.contactPersonInfoTelephone
}
const resp = await api.post('/enterprisesUnit/saveOrUpdate', params)
message.success(resp.message)
await _tableRef.value?.requestGetTableData()
}
})
}
const _tableRef = ref<ComponentExposed<typeof TableProMax>>(null)
const _columns: _TableProps['columns'] = [
{
dataIndex: 'name',
title: '名称'
}, {
dataIndex: 'contactPersonInfo',
title: '联系人',
customRender: ({text}) => text?.name + "/" + text.telephone
}, {
dataIndex: 'province',
title: '行政区划',
customRender: ({record}) => [record.provinceName, record.cityName, record.districtsName, record.streetName].filter(Boolean).join("/")
}, {
dataIndex: 'address',
title: '详细地址'
}, {
dataIndex: 'remark',
title: '备注'
}, {
dataIndex: 'createTime',
title: '创建时间'
}, {
dataIndex: 'opt',
title: '操作',
customRender: ({record}) => <a-space>
<a-button
class="btn-warn"
onClick={() => saveOrUpdateEnterprisesUnit({
snowFlakeId: record.snowFlakeId,
policeUnitId: record.policeUnitId,
name: record.name,
administrativeDivisionCodes: [record.province, record.city, record.districts, record.street].filter(Boolean),
address: record.address,
contactPersonInfoName: record.contactPersonInfo?.name,
contactPersonInfoTelephone: record.contactPersonInfo?.telephone,
remark: record.remark
})}
>编辑
</a-button>
</a-space>
}
]
const _reqApi: _TableProps["requestApi"] = (params) => {
(params as PageParams<EnterprisesUnitPagerQueryParams>).params.policeUnitId = policeUnitPagerVo.snowFlakeId
return api.post('/enterprisesUnit/pager', params)
}
Modal.info({
title: `${policeUnitPagerVo.name}】 管辖企事业单位`,
width: '80%',
content: () => <TableProMax
ref={_tableRef}
columns={_columns}
requestApi={_reqApi}
v-slots={{
tableHeader: (_) => {
return <a-space>
<a-button
class="btn-success"
onClick={() => saveOrUpdateEnterprisesUnit({
name: undefined,
policeUnitId: policeUnitPagerVo.snowFlakeId,
administrativeDivisionCodes: [policeUnitPagerVo.province, policeUnitPagerVo.city, policeUnitPagerVo.districts, policeUnitPagerVo.street].filter(Boolean)
})}
>新增
</a-button>
<a-button disabled>导入</a-button>
</a-space>
}
} as TableProMaxSlots<PoliceUnitPagerVo>}
/>
})
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -17,8 +17,10 @@ import {SecurityUnitPagerQueryParams, SecurityUnitPagerVo} from "@/types/views/u
import api from "@/axios"; import api from "@/axios";
import {ref} from "vue"; import {ref} from "vue";
import {ComponentExposed} from "vue-component-type-helpers"; import {ComponentExposed} from "vue-component-type-helpers";
import {enumSelectNodes} from "@/config/dict.ts"; import {dictSelectNodes} from "@/config/dict.ts";
import {message} from "ant-design-vue"; import {message} from "ant-design-vue";
import {UNIT_TYPE} from "@/config";
type TableProps = TableProMaxProps<SecurityUnitPagerVo, SecurityUnitPagerQueryParams> type TableProps = TableProMaxProps<SecurityUnitPagerVo, SecurityUnitPagerQueryParams>
@ -85,7 +87,7 @@ const columns: TableProps['columns'] = [
onConfirm={async () => { onConfirm={async () => {
const resp = await api.post('/management/checkPass', { const resp = await api.post('/management/checkPass', {
checkDataId: record.snowFlakeId, checkDataId: record.snowFlakeId,
unitOptType: 'SECURITY_UNIT' unitOptType: UNIT_TYPE.security
}) })
message.success(resp.message) message.success(resp.message)
await tableRef.value?.requestGetTableData() await tableRef.value?.requestGetTableData()
@ -94,7 +96,17 @@ const columns: TableProps['columns'] = [
</a-button> </a-button>
</a-popconfirm> </a-popconfirm>
} }
{record.isEnable.value === 0 ? <a-button danger>禁用</a-button> : <a-button></a-button>} <a-button
class={record.isEnable.value === 0 ? 'btn-danger' : 'btn-success'}
onClick={async () => {
const resp = await api.post('/management/disableOrEnable', {
unitId: record.snowFlakeId,
unitOptType: UNIT_TYPE.security
})
message.success(resp.message)
await tableRef.value?.requestGetTableData()
}}
>{record.isEnable.value === 0 ? '禁用' : '启用'}</a-button>
</a-space> </a-space>
}, },
width: 200 width: 200
@ -115,7 +127,7 @@ const searchFormOptions: TableProps["searchFormOptions"] = {
{ {
value: null, value: null,
label: '全部' label: '全部'
}, ...enumSelectNodes('IsEnable') }, ...dictSelectNodes('IsEnable')
] ]
}, checkStatus: { }, checkStatus: {
type: 'select', type: 'select',
@ -124,7 +136,7 @@ const searchFormOptions: TableProps["searchFormOptions"] = {
{ {
value: null, value: null,
label: '全部' label: '全部'
}, ...enumSelectNodes('CheckStatus') }, ...dictSelectNodes('CheckStatus')
] ]
} }
} }