huangxw 7 mesi fa
parent
commit
f0d5865bfa
100 ha cambiato i file con 8083 aggiunte e 3 eliminazioni
  1. 2 1
      package.json
  2. 49 0
      src/api/adcd/index.ts
  3. 52 0
      src/api/auth/user/index.ts
  4. 238 0
      src/api/auth/user/types.ts
  5. 109 0
      src/api/enterprise/recordCompany/index.ts
  6. 504 0
      src/api/enterprise/recordCompany/types.ts
  7. 26 0
      src/api/gb/index.ts
  8. 27 0
      src/api/h5-custom/index.ts
  9. 101 0
      src/api/permission/application/index.ts
  10. 195 0
      src/api/permission/application/types.ts
  11. 63 0
      src/api/permission/partner/index.ts
  12. 141 0
      src/api/permission/partner/types.ts
  13. 83 0
      src/api/settled/index.ts
  14. 63 0
      src/api/smarttrace/article/index.ts
  15. 319 0
      src/api/smarttrace/article/types.ts
  16. 63 0
      src/api/smarttrace/category/index.ts
  17. 146 0
      src/api/smarttrace/category/types.ts
  18. 76 0
      src/api/smarttrace/companyCertificate/index.ts
  19. 191 0
      src/api/smarttrace/companyCertificate/types.ts
  20. 85 0
      src/api/smarttrace/companyFieldApply/index.ts
  21. 195 0
      src/api/smarttrace/companyFieldApply/types.ts
  22. 63 0
      src/api/smarttrace/dataEnterprise/index.ts
  23. 151 0
      src/api/smarttrace/dataEnterprise/types.ts
  24. 63 0
      src/api/smarttrace/dataHonor/index.ts
  25. 91 0
      src/api/smarttrace/dataHonor/types.ts
  26. 63 0
      src/api/smarttrace/dataProduct/index.ts
  27. 181 0
      src/api/smarttrace/dataProduct/types.ts
  28. 72 0
      src/api/smarttrace/geoIdentityApply/index.ts
  29. 331 0
      src/api/smarttrace/geoIdentityApply/types.ts
  30. 63 0
      src/api/smarttrace/section/index.ts
  31. 176 0
      src/api/smarttrace/section/types.ts
  32. 74 0
      src/api/smarttrace/site/index.ts
  33. 131 0
      src/api/smarttrace/site/types.ts
  34. BIN
      src/assets/images/cloud.png
  35. BIN
      src/assets/images/cpy_sld.png
  36. BIN
      src/assets/images/cpy_slx.png
  37. 39 0
      src/assets/images/dark copy.svg
  38. BIN
      src/assets/images/earth_bg.png
  39. BIN
      src/assets/images/ground.png
  40. BIN
      src/assets/images/icon_pic.png
  41. BIN
      src/assets/images/login.gif
  42. BIN
      src/assets/images/login_border.png
  43. BIN
      src/assets/images/login_horizontal_line.png
  44. BIN
      src/assets/images/login_human.png
  45. BIN
      src/assets/images/nodata.jpg
  46. BIN
      src/assets/images/sky.png
  47. BIN
      src/assets/images/starflake1.png
  48. BIN
      src/assets/images/starflake2.png
  49. 3 0
      src/assets/svg/a_icon.svg
  50. 6 0
      src/assets/svg/back_icon.svg
  51. 3 0
      src/assets/svg/check_card_icon.svg
  52. 3 0
      src/assets/svg/ck_icon.svg
  53. 3 0
      src/assets/svg/clear_icon.svg
  54. 3 0
      src/assets/svg/delete_icon.svg
  55. 3 0
      src/assets/svg/dw_icon.svg
  56. 3 0
      src/assets/svg/edit_icon.svg
  57. 8 0
      src/assets/svg/land_bg.svg
  58. 3 0
      src/assets/svg/land_icon.svg
  59. 6 0
      src/assets/svg/log_icon.svg
  60. 3 0
      src/assets/svg/look_icon.svg
  61. 3 0
      src/assets/svg/no_pass_icon.svg
  62. 6 0
      src/assets/svg/normal_u143.svg
  63. 6 0
      src/assets/svg/normal_u190.svg
  64. 3 0
      src/assets/svg/normal_u191.svg
  65. 10 0
      src/assets/svg/normal_u27.svg
  66. 3 0
      src/assets/svg/normal_u55.svg
  67. 3 0
      src/assets/svg/pass_icon.svg
  68. 6 0
      src/assets/svg/uplod_icon.svg
  69. 6 0
      src/assets/svg/uploud_icon.svg
  70. 124 0
      src/components/PhotoUpload/index.vue
  71. 75 0
      src/utils/models.ts
  72. 1 1
      src/utils/request.ts
  73. 12 0
      src/utils/ruoyi.ts
  74. 346 0
      src/views/auth/appuser/index.vue
  75. 209 0
      src/views/auth/appuser/userbind.vue
  76. 108 0
      src/views/components/AreaCascader.vue
  77. 47 0
      src/views/components/AreaView.vue
  78. 15 0
      src/views/components/Breadcrumb.vue
  79. 37 0
      src/views/components/DateRange.vue
  80. 16 0
      src/views/components/DescInfo.vue
  81. 36 0
      src/views/components/DescItem.vue
  82. 38 0
      src/views/components/DescItemTop.vue
  83. 63 0
      src/views/components/FileLook.vue
  84. 51 0
      src/views/components/H5ModelLook.vue
  85. 24 0
      src/views/components/ImageViewer.vue
  86. 314 0
      src/views/components/MapContainer.vue
  87. 239 0
      src/views/components/UploadAvatar.vue
  88. 5 0
      src/views/components/VueDrag.vue
  89. 21 0
      src/views/components/index.ts
  90. 54 0
      src/views/components/searchTabs.vue
  91. 14 0
      src/views/components/types.ts
  92. 424 0
      src/views/enterprise/recordCompany/index.vue
  93. 198 0
      src/views/h5-custom/list/index.vue
  94. 1 1
      src/views/leader/declaration-detail/index.vue
  95. 1 0
      src/views/leader/declaration-record/index.vue
  96. 453 0
      src/views/permission/application/index.vue
  97. 558 0
      src/views/permission/partner/index.vue
  98. 187 0
      src/views/settled/control/index.vue
  99. 86 0
      src/views/settled/cpy/index.vue
  100. 7 0
      src/views/settled/index.ts

+ 2 - 1
package.json

@@ -22,6 +22,7 @@
     "url": "https://gitee.com/JavaLionLi/plus-ui.git"
   },
   "dependencies": {
+    "@amap/amap-jsapi-loader": "^1.0.1",
     "@element-plus/icons-vue": "2.3.1",
     "@highlightjs/vue-plugin": "2.1.0",
     "@vueup/vue-quill": "1.2.0",
@@ -89,4 +90,4 @@
     "vitest": "1.5.0",
     "vue-tsc": "2.0.13"
   }
-}
+}

+ 49 - 0
src/api/adcd/index.ts

@@ -0,0 +1,49 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+
+/**
+ * 查询行政区划信息列表
+ * @param query
+ * @returns {*}
+ */
+export const adcdList = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/adcd/list',
+        method: 'get',
+        params: query
+    });
+};
+/**
+ * 查询行政区划信息列表 传父级编码查询
+ * @param query
+ * @returns {*}
+ */
+export const listChildrenByCode = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/adcd/listChildrenByCode',
+        method: 'get',
+        params: query
+    });
+};
+/**
+ * 获取行政区划信息详细信息
+ * @param query
+ * @returns {*}
+ */
+export const adcdInfo = (id?: any): AxiosPromise<any> => {
+    return request({
+        url: `/adcd/getInfo/${id}`,
+        method: 'get'
+    });
+};
+/**
+ * 获取行政区划信息详细信息
+ * @param query
+ * @returns {*}
+ */
+export const getAdcdByCode = (code?: any): AxiosPromise<any> => {
+    return request({
+        url: `/adcd/getByCode/${code}`,
+        method: 'get'
+    });
+};

+ 52 - 0
src/api/auth/user/index.ts

@@ -0,0 +1,52 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { UserVO, UserForm, UserQuery } from '@/api/auth/user/types';
+
+/**
+ * 查询app用户列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listUser = (query?: UserQuery): AxiosPromise<UserVO[]> => {
+  return request({
+    url: '/appuser/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询app用户详细
+ * @param id
+ */
+export const getUser = (id: string | number): AxiosPromise<UserVO> => {
+  return request({
+    url: '/auth/user/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+
+/**
+ * 修改app用户
+ * @param data
+ */
+export const updateUser = (data: UserForm) => {
+  return request({
+    url: '/appuser/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除app用户
+ * @param id
+ */
+export const delUser = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/auth/user/remove/' + id,
+    method: 'get'
+  });
+};

+ 238 - 0
src/api/auth/user/types.ts

@@ -0,0 +1,238 @@
+export interface UserVO {
+    /**
+     * ID
+     */
+    id: string | number;
+
+    /**
+     * 姓名
+     */
+    name: string;
+
+    /**
+     * 证件号码
+     */
+    idcard: string | number;
+
+    /**
+     * 用户昵称
+     */
+    nickName: string;
+
+    /**
+     * 用户头像
+     */
+    avatar: string;
+
+    /**
+     * unionid
+     */
+    unionid: string | number;
+
+    /**
+     * 电话号码
+     */
+    phone: string;
+
+    /**
+     * 邮箱
+     */
+    email: string;
+
+    /**
+     * 密码
+     */
+    pwd: string;
+
+    /**
+     * 状态
+     */
+    status: string;
+
+    /**
+     * 当前企业id
+     */
+    currentCpyid: string | number;
+
+    /**
+     * 会员标志
+     */
+    vipFlag: string;
+
+    /**
+     * 会员开始时间
+     */
+    vipStart: string;
+
+    /**
+     * 会员结束时间
+     */
+    vipEnd: string;
+
+    /**
+     * 创建人
+     */
+    createBy: string;
+
+    /**
+     * 创建时间
+     */
+    createTime: string;
+
+    /**
+     * 更新时间
+     */
+    updateTime: string;
+}
+
+export interface UserForm extends BaseEntity {
+    /**
+     * ID
+     */
+    id?: string | number;
+
+    /**
+     * 姓名
+     */
+    name?: string;
+
+    /**
+     * 证件号码
+     */
+    idcard?: string | number;
+
+    /**
+     * 用户昵称
+     */
+    nickName?: string;
+
+    /**
+     * 用户头像
+     */
+    avatar?: string;
+
+    /**
+     * unionid
+     */
+    unionid?: string | number;
+
+    /**
+     * 电话号码
+     */
+    phone?: string;
+
+    /**
+     * 邮箱
+     */
+    email?: string;
+
+    /**
+     * 密码
+     */
+    pwd?: string;
+
+    /**
+     * 状态
+     */
+    status?: string;
+
+    /**
+     * 当前企业id
+     */
+    currentCpyid?: string | number;
+
+    /**
+     * 会员标志
+     */
+    vipFlag?: string;
+
+    /**
+     * 会员开始时间
+     */
+    vipStart?: string;
+
+    /**
+     * 会员结束时间
+     */
+    vipEnd?: string;
+}
+
+export interface UserQuery extends PageQuery {
+    /**
+     * 姓名
+     */
+    name?: string;
+
+    /**
+     * 证件号码
+     */
+    idcard?: string | number;
+
+    /**
+     * 用户昵称
+     */
+    nickName?: string;
+
+    /**
+     * 用户头像
+     */
+    avatar?: string;
+
+    /**
+     * unionid
+     */
+    unionid?: string | number;
+
+    /**
+     * 电话号码
+     */
+    phone?: string;
+
+    /**
+     * 邮箱
+     */
+    email?: string;
+
+    /**
+     * 密码
+     */
+    pwd?: string;
+
+    /**
+     * 状态
+     */
+    status?: string;
+
+    /**
+     * 当前企业id
+     */
+    currentCpyid?: string | number;
+
+    /**
+     * 会员标志
+     */
+    vipFlag?: string;
+
+    /**
+     * 会员开始时间
+     */
+    vipStart?: string;
+
+    /**
+     * 会员结束时间
+     */
+    vipEnd?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+    /**
+     * 是否绑定邮箱
+     */
+    emailbind?: string;
+    /**
+     * 是否绑定公众号
+     */
+    wxbind?: string;
+}

+ 109 - 0
src/api/enterprise/recordCompany/index.ts

@@ -0,0 +1,109 @@
+import { RecordCompanyForm, RecordCompanyQuery, RecordCompanyVO, BindInfoRemoveBo, AdminOperateUserBo, QueryUserBindInfoBo } from '@/api/enterprise/recordCompany/types';
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+
+/**
+ * 查询企业备案信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listRecordCompany = (query?: RecordCompanyQuery): AxiosPromise<RecordCompanyVO[]> => {
+    return request({
+        url: '/company/listByPage',
+        method: 'get',
+        params: query
+    });
+};
+
+/**
+ * 查询企业备案信息详细
+ * @param id
+ */
+export const getRecordCompany = (id: string | number): AxiosPromise<RecordCompanyVO> => {
+    return request({
+        url: '/company/detail/' + id,
+        method: 'get'
+    });
+};
+
+/**
+ * 新增企业备案信息
+ * @param data
+ */
+export const addRecordCompany = (data: RecordCompanyForm) => {
+    return request({
+        url: '/enterprise/recordCompany/add',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 修改企业备案信息
+ * @param data
+ */
+export const updateRecordCompany = (data: RecordCompanyForm) => {
+    return request({
+        url: '/company/adminModify',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 删除企业备案信息
+ * @param id
+ */
+export const delRecordCompany = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/enterprise/recordCompany/remove/' + id,
+        method: 'get'
+    });
+};
+/**
+ * 企业备案审批
+ * @param data
+ */
+export const companyApproval = (data: RecordCompanyForm) => {
+    return request({
+        url: '/approval/approvalCpy',
+        method: 'post',
+        data: data
+    });
+};
+
+export const listByUserId = (userId: string | number): AxiosPromise<any> => {
+    return request({
+        url: '/company/listByUserId/' + userId,
+        method: 'get'
+    });
+};
+
+export const removeBindUser = (data: BindInfoRemoveBo): AxiosPromise<any> => {
+    return request({
+        url: '/bindInfo/removeUser',
+        method: 'post',
+        data
+    });
+};
+export const adminAddUserForCpy = (data: AdminOperateUserBo): AxiosPromise<any> => {
+    return request({
+        url: '/bindInfo/adminAddUserForCpy',
+        method: 'get',
+        params: data
+    });
+};
+
+/**
+ * 查询用户绑定信息列表
+ * @param query
+ * @returns {*}
+ */
+export const listUserBindInfo = (query?: QueryUserBindInfoBo): AxiosPromise<any> => {
+    return request({
+        url: '/bindInfo/listByPageAll',
+        method: 'get',
+        params: query
+    });
+};

+ 504 - 0
src/api/enterprise/recordCompany/types.ts

@@ -0,0 +1,504 @@
+export interface RecordCompanyVO {
+  /**
+   * Id
+   */
+  id: string | number;
+
+  /**
+   * 企业简称
+   */
+  cpyAbbreviation: string;
+
+  /**
+   * 企业名称
+   */
+  cpyName: string;
+
+  /**
+   * 法人身份证
+   */
+  cpyIdCard: string | number;
+
+  /**
+   * 电话
+   */
+  tel: string;
+
+  /**
+   * 法人
+   */
+  legalPerson: string;
+
+  /**
+   * 信用代码
+   */
+  creditCode: string;
+
+  /**
+   * 审核状态 字典:0未通过,1通过,-1待审核
+   */
+  status: number;
+
+  /**
+   * 企业状态 字典:0注销,1在业,2暂停营业
+   */
+  companyStatus: number;
+
+  /**
+   * 行政区划代码
+   */
+  adcdCode: string;
+
+  /**
+   * 门店照片
+   */
+  storePhoto: string;
+
+  /**
+   * 营业执照
+   */
+  businesPhoto: string;
+
+  /**
+   * 经营范围
+   */
+  businessScope: string;
+
+  /**
+   * 地址
+   */
+  address: string;
+
+  /**
+   * 联系人
+   */
+  contactPerson: string;
+
+  /**
+   * 经度
+   */
+  longitude: string;
+
+  /**
+   * 纬度
+   */
+  latitude: string;
+
+  /**
+   * 营业执照
+   */
+  licenseUrl: string;
+
+  /**
+   * 营业执照有效期
+   */
+  licenseValidity: string | number;
+
+  /**
+   * 追溯类型
+   */
+  recordTraceType: string;
+
+  /**
+   * 追溯环节
+   */
+  recordTraceLink: string;
+
+  /**
+   * 企业管理员
+   */
+  adminId: string | number;
+
+  /**
+   * 管理员姓名
+   */
+  adminName: string;
+
+  /**
+   * 上链标志
+   */
+  chainStatus: string;
+
+  /**
+   * 上联备注
+   */
+  chainRmk: string;
+
+  /**
+   * 营业执照开始日期
+   */
+  businessStartDate: string;
+
+  /**
+   * 营业执照有效期
+   */
+  deadline: string;
+
+  /**
+   * 加入的合作伙伴
+   */
+  joinPartner: string;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId: string | number;
+
+  /**
+   * 申请者id
+   */
+  userid: string | number;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+}
+
+export interface RecordCompanyForm extends BaseEntity {
+  /**
+   * Id
+   */
+  id?: string | number;
+
+  /**
+   * 企业名称
+   */
+  cpyName?: string;
+  /**
+   * 企业类型
+   */
+  cpyType?: string;
+
+  /**
+   * 电话
+   */
+  tel?: string;
+
+  /**
+   * 信用代码
+   */
+  creditCode?: string;
+
+  /**
+   * 审核状态 字典:0未通过,1通过,-1待审核
+   */
+  status?: number;
+
+  /**
+   * 行政区划代码
+   */
+  adcdCode?: string;
+
+  /**
+   * 企业logo
+   */
+  storePhoto?: string;
+
+  /**
+   * 地址
+   */
+  address?: string;
+
+  /**
+   * 联系人
+   */
+  contactPerson?: string;
+
+  /**
+   * 营业执照
+   */
+  license?: any;
+
+  /**
+   * 企业管理员
+   */
+  adminId?: string | number;
+
+  /**
+   * 管理员姓名
+   */
+  adminName?: string;
+
+  /**
+   * 申请者id
+   */
+  userid?: string | number;
+}
+
+export interface RecordCompanyQuery extends PageQuery {
+  /**
+   * 企业简称
+   */
+  cpyAbbreviation?: string;
+
+  /**
+   * 企业名称
+   */
+  cpyName?: string;
+
+  /**
+   * 法人身份证
+   */
+  cpyIdCard?: string | number;
+
+  /**
+   * 电话
+   */
+  tel?: string;
+
+  /**
+   * 法人
+   */
+  legalPerson?: string;
+
+  /**
+   * 信用代码
+   */
+  creditCode?: string;
+
+  /**
+   * 审核状态 字典:0未通过,1通过,-1待审核
+   */
+  status?: number | string;
+
+  /**
+   * 企业状态 字典:0注销,1在业,2暂停营业
+   */
+  companyStatus?: number;
+
+  /**
+   * 行政区划代码
+   */
+  adcdCode?: string;
+
+  /**
+   * 门店照片
+   */
+  storePhoto?: string;
+
+  /**
+   * 营业执照
+   */
+  businesPhoto?: string;
+
+  /**
+   * 经营范围
+   */
+  businessScope?: string;
+
+  /**
+   * 地址
+   */
+  address?: string;
+
+  /**
+   * 联系人
+   */
+  contactPerson?: string;
+
+  /**
+   * 经度
+   */
+  longitude?: string;
+
+  /**
+   * 纬度
+   */
+  latitude?: string;
+
+  /**
+   * 营业执照
+   */
+  licenseUrl?: string;
+
+  /**
+   * 营业执照有效期
+   */
+  licenseValidity?: string | number;
+
+  /**
+   * 追溯类型
+   */
+  recordTraceType?: string;
+
+  /**
+   * 追溯环节
+   */
+  recordTraceLink?: string;
+
+  /**
+   * 企业管理员
+   */
+  adminId?: string | number;
+
+  /**
+   * 管理员姓名
+   */
+  adminName?: string;
+
+  /**
+   * 上链标志
+   */
+  chainStatus?: string;
+
+  /**
+   * 上联备注
+   */
+  chainRmk?: string;
+
+  /**
+   * 营业执照开始日期
+   */
+  businessStartDate?: string;
+
+  /**
+   * 营业执照有效期
+   */
+  deadline?: string;
+
+  /**
+   * 加入的合作伙伴
+   */
+  joinPartner?: string;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+  /**
+   * 申请者id
+   */
+  userid?: string | number;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}
+
+/**
+ * BindInfoCpyListVo,绑定企业信息
+ */
+export interface BindInfoCpyListVo {
+  /**
+   * 审核人
+   */
+  auditor?: number;
+  /**
+   * 审核人姓名
+   */
+  auditorName?: string;
+  /**
+   * 审核时间
+   */
+  auditorTime?: Date;
+  /**
+   * 企业ID
+   */
+  cpyid?: number;
+
+  cpyInfo?: RecordCompanyVO;
+  /**
+   * 创建人
+   */
+  createBy?: string;
+  /**
+   * 创建时间
+   */
+  createTime?: Date;
+  /**
+   * ID
+   */
+  id?: number;
+  /**
+   * 审核信息
+   */
+  msg?: string;
+  /**
+   * 通过时间
+   */
+  passTime?: Date;
+  /**
+   * 审核结果:0:等待审核,1:通过,2:不通过
+   */
+  res?: string;
+  /**
+   * 绑定类型:1企业备案绑定,2用户主动绑定
+   */
+  type?: string;
+  /**
+   * 申请者id
+   */
+  userid?: number;
+  /**
+   * 申请人名称
+   */
+  userName?: string;
+  /**
+   * 申请信息
+   */
+  wantMsg?: string;
+
+}
+/**
+ * BindInfoRemoveBo,审核日志业务对象 st_bind_info
+ */
+export interface BindInfoRemoveBo {
+  /**
+   * 企业ID
+   */
+  cpyid: number;
+  /**
+   * 成员ID
+   */
+  userids: number[];
+}
+
+export interface AdminOperateUserBo {
+  /**
+   * 企业ID
+   */
+  cpyid: number;
+  /**
+   * 用户ID
+   */
+  userid: number;
+}
+/**
+ * 查询用户申请绑定信息
+ */
+export interface QueryUserBindInfoBo extends PageQuery {
+  /**
+   * 企业名称
+   */
+  cpyName: any;
+  /**
+   * 关键字
+   */
+  keywords: any;
+  /**
+   * 用户姓名
+   */
+  userName: any;
+  /**
+   * 状态
+   */
+  status: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 26 - 0
src/api/gb/index.ts

@@ -0,0 +1,26 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+/**
+ * 三无一权生成码申请列表
+ * @param query
+ * @returns {*}
+ */
+export const swyqCodeLogList = (query?: any): AxiosPromise<any[]> => {
+    return request({
+        url: '/smarttrace/gbCodeLog/swyqCodeLogList',
+        method: 'get',
+        params: query
+    });
+};
+/**
+ * 三无一权生成码申请审批
+ * @param query
+ * @returns {*}
+ */
+export const approvalSwyqCodeLog = (query?: any): AxiosPromise<any[]> => {
+    return request({
+        url: '/smarttrace/gbCodeLog/approvalSwyqCodeLog',
+        method: 'post',
+        data: query
+    });
+};

+ 27 - 0
src/api/h5-custom/index.ts

@@ -0,0 +1,27 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+/**
+ * 查询H5自定义模版列表
+ * @param query
+ * @returns {*}
+ */
+
+export const h5TplList = (query?: any): AxiosPromise<any[]> => {
+    return request({
+        url: '/smarttrace/h5Tpl/list',
+        method: 'get',
+        params: query
+    });
+};
+/**
+ * 管理员H5模板审批
+ * @param query
+ * @returns {*}
+ */
+export const h5TplApprove = (query: any): AxiosPromise<any> => {
+    return request({
+        url: '/smarttrace/h5Tpl/approvalH5',
+        method: 'post',
+        data: query
+    });
+};

+ 101 - 0
src/api/permission/application/index.ts

@@ -0,0 +1,101 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ApplicationVO, ApplicationForm, ApplicationQuery } from '@/api/permission/application/types';
+
+/**
+ * 查询应用信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listApplication = (query?: any): AxiosPromise<any[]> => {
+    return request({
+        url: '/perm/application/list',
+        method: 'get',
+        params: query
+    });
+};
+
+/**
+ * 查询应用信息详细
+ * @param id
+ */
+export const getApplication = (id: string | number): AxiosPromise<ApplicationVO> => {
+    return request({
+        url: '/perm/application/getInfo/' + id,
+        method: 'get'
+    });
+};
+
+/**
+ * 新增应用信息
+ * @param data
+ */
+export const addApplication = (data: ApplicationForm) => {
+    return request({
+        url: '/perm/application/create',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 修改应用信息
+ * @param data
+ */
+export const updateApplication = (data: ApplicationForm) => {
+    return request({
+        url: '/perm/application/edit',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 删除应用信息
+ * @param id
+ */
+export const delApplication = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/perm/application/remove/' + id,
+        method: 'get'
+    });
+};
+export const ApplicationOnshelf = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/perm/application/onshelf/' + id,
+        method: 'get'
+    });
+};
+export const ApplicationLeaveshelf = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/perm/application/leaveshelf/' + id,
+        method: 'get'
+    });
+};
+/**
+ * 查询应用信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listApplicationQx = (query?: ApplicationQuery): AxiosPromise<ApplicationVO[]> => {
+    return request({
+        url: '/perm/application/listQx',
+        method: 'get',
+        params: query
+    });
+};
+/**
+ * 查询应用信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listApplicationOther = (query?: ApplicationQuery): AxiosPromise<ApplicationVO[]> => {
+    return request({
+        url: '/perm/application/listOther',
+        method: 'get',
+        params: query
+    });
+};

+ 195 - 0
src/api/permission/application/types.ts

@@ -0,0 +1,195 @@
+export interface ApplicationVO {
+    /**
+     * ID
+     */
+    id?: string | number;
+
+    /**
+     * 应用名称
+     */
+    applicationName?: string;
+
+    /**
+     * 图标
+     */
+    icon?: string;
+
+    /**
+     * 跳转地址
+     */
+    url?: string;
+
+    /**
+     * 应用类型
+     */
+    type?: string;
+
+    /**
+     * 状态
+     */
+    status?: string;
+
+    /**
+     * 备注
+     */
+    remark?: string;
+
+    /**
+     * 创建人
+     */
+    createBy?: string;
+
+    /**
+     * 创建时间
+     */
+    createTime?: string;
+
+    /**
+     * 更新时间
+     */
+    updateTime?: string;
+
+    /**
+     * 原始应用id
+     */
+    originId?: number;
+    /**
+     * 合作伙伴id
+     */
+    partnerId?: number;
+
+    precondition: CpyTypeDTO[];
+
+
+    bgUrl?:string;
+}
+export interface KeyInfo {
+    partnerPubKey?: string;
+    partnerPriKey?: string;
+    appid?: string;
+    secret?: string;
+}
+export interface ApplicationForm extends BaseEntity {
+    /**
+     * ID
+     */
+    id?: string | number;
+
+    /**
+     * 应用名称
+     */
+    applicationName?: string;
+    /**
+     * 结束日期
+     */
+    endAt?: Date;
+    /**
+     * 图标
+     */
+    icon?: string;
+
+    /**
+     * 密钥信息
+     */
+    keyInfo: KeyInfo;
+    /**
+     * 原始应用id
+     */
+    originId?: number;
+    /**
+     * 合作伙伴id
+     */
+    partnerId?: number;
+    /**
+     * 备注
+     */
+    remark?: string;
+    /**
+     * 开始日期
+     */
+    startAt?: Date;
+    /**
+     * 应用类型 1 web应用 2 小程序应用
+     */
+    type?: string;
+    /**
+     * 跳转地址
+     */
+    url?: string;
+    /**
+     * 背景
+     */
+    bgUrl?: string;
+    /**
+     * 需要资质
+     */
+    precondition: CpyTypeDTO[];
+
+    sort?: number;
+
+    btnConf?: string
+
+}
+
+export interface CpyTypeDTO {
+    /**
+     * 企业类型
+     */
+    cpyType?: string;
+    /**
+     * 行业类型
+     */
+    industryType?: string;
+}
+
+export interface ApplicationQuery extends PageQuery {
+    /**
+     * 应用名称
+     */
+    applicationName?: string;
+    /**
+     * 创建者
+     */
+    createBy?: number;
+    /**
+     * 创建部门
+     */
+    createDept?: number;
+    /**
+     * 创建时间
+     */
+    createTime?: string;
+    /**
+     * 图标
+     */
+    icon?: string;
+    /**
+     * ID
+     */
+    id?: number;
+    /**
+     * 备注
+     */
+    remark?: string;
+    /**
+     * 状态 0 未上架 1 已上架
+     */
+    status?: string;
+    /**
+     * 应用类型 1 web应用 2 小程序应用
+     */
+    type?: string;
+    /**
+     * 跳转地址
+     */
+    url?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+
+    partnerId?: number | string;
+
+    bgUrl?:string;
+}

+ 63 - 0
src/api/permission/partner/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PartnerVO, PartnerForm, PartnerQuery } from '@/api/permission/partner/types';
+
+/**
+ * 查询合作伙伴信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPartner = (query?: PartnerQuery): AxiosPromise<PartnerVO[]> => {
+  return request({
+    url: '/perm/partner/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询合作伙伴信息详细
+ * @param id
+ */
+export const getPartner = (id: string | number): AxiosPromise<PartnerVO> => {
+  return request({
+    url: '/perm/partner/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增合作伙伴信息
+ * @param data
+ */
+export const addPartner = (data: PartnerForm) => {
+  return request({
+    url: '/perm/partner/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改合作伙伴信息
+ * @param data
+ */
+export const updatePartner = (data: PartnerForm) => {
+  return request({
+    url: '/perm/partner/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除合作伙伴信息
+ * @param id
+ */
+export const delPartner = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/perm/partner/remove/' + id,
+    method: 'get'
+  });
+};

+ 141 - 0
src/api/permission/partner/types.ts

@@ -0,0 +1,141 @@
+export interface PartnerVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 合作伙伴名称
+   */
+  partnerName: string;
+
+  /**
+   * 合作伙伴编码
+   */
+  partnerCode: string;
+
+  /**
+   * 合作伙伴公钥
+   */
+  key: string;
+
+  /**
+   * 授权开始时间
+   */
+  startAt: string;
+
+  /**
+   * 授权结束时间
+   */
+  endAt: string;
+
+  /**
+   * 状态
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface PartnerForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 合作伙伴名称
+   */
+  partnerName?: string;
+
+  /**
+   * 合作伙伴编码
+   */
+  partnerCode?: string;
+
+  /**
+   * 合作伙伴公钥
+   */
+  key?: string;
+
+  /**
+   * 授权开始时间
+   */
+  startAt?: string;
+
+  /**
+   * 授权结束时间
+   */
+  endAt?: string;
+
+  /**
+   * 状态
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface PartnerQuery extends PageQuery {
+
+  /**
+   * 合作伙伴名称
+   */
+  partnerName?: string;
+
+  /**
+   * 合作伙伴编码
+   */
+  partnerCode?: string;
+
+  /**
+   * 合作伙伴公钥
+   */
+  key?: string;
+
+  /**
+   * 授权开始时间
+   */
+  startAt?: string;
+
+  /**
+   * 授权结束时间
+   */
+  endAt?: string;
+
+  /**
+   * 状态
+   */
+  status?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 83 - 0
src/api/settled/index.ts

@@ -0,0 +1,83 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+/**
+ * 查询应用信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const companyMembers = (query?: any): AxiosPromise<any[]> => {
+    return request({
+        url: '/company/members',
+        method: 'post',
+        data: query
+    });
+};
+export const removeUser = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/bindInfo/removeUser',
+        method: 'post',
+        data: query
+    });
+};
+export const companyDetail = (id?: any): AxiosPromise<any> => {
+    return request({
+        url: `/company/detail/${id}`,
+        method: 'get'
+    });
+};
+// 设为管理员
+export const settingCpyAdmin = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/bindInfo/settingCpyAdmin',
+        method: 'get',
+        params: query
+    });
+};
+// 后台-绑定申请审批
+export const bindInfoApproval = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/bindInfo/approval',
+        method: 'post',
+        data: query
+    });
+};
+// 后台-绑定申请审批
+export const companyCertificatelist = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/companyCertificate/queryList',
+        method: 'get',
+        params: query
+    });
+};
+// 管理员取消认证
+export const cancelCert = (id?: any): AxiosPromise<any> => {
+    return request({
+        url: `/companyCertificate/cancelCert/${id}`,
+        method: 'get'
+    });
+};
+// 后台-企业认证审批
+export const approvalCert = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/approval/approvalCert',
+        method: 'post',
+        data: query
+    });
+};
+// 后台-企业批量授权应用
+export const batchGrant = (query?: any): AxiosPromise<any> => {
+    return request({
+        url: '/perm/applicationcpy/batchGrant',
+        method: 'post',
+        data: query
+    });
+};
+// 后台-企业批量授权应用
+export const batchRemove = (query?: any, cpyId?: any): AxiosPromise<any> => {
+    return request({
+        url: `/perm/applicationcpy/batchRemove/${cpyId}`,
+        method: 'post',
+        data: query
+    });
+};

+ 63 - 0
src/api/smarttrace/article/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ArticleVO, ArticleForm, ArticleQuery } from '@/api/smarttrace/article/types';
+
+/**
+ * 查询文章列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listArticle = (query?: ArticleQuery): AxiosPromise<ArticleVO[]> => {
+  return request({
+    url: '/smarttrace/article/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询文章详细
+ * @param id
+ */
+export const getArticle = (id: string | number): AxiosPromise<ArticleVO> => {
+  return request({
+    url: '/smarttrace/article/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增文章
+ * @param data
+ */
+export const addArticle = (data: ArticleForm) => {
+  return request({
+    url: '/smarttrace/article/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改文章
+ * @param data
+ */
+export const updateArticle = (data: ArticleForm) => {
+  return request({
+    url: '/smarttrace/article/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除文章
+ * @param id
+ */
+export const delArticle = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/article/remove/' + id,
+    method: 'get'
+  });
+};

+ 319 - 0
src/api/smarttrace/article/types.ts

@@ -0,0 +1,319 @@
+export interface ArticleVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 站点ID
+   */
+  siteId: string | number;
+
+  /**
+   * 栏目id
+   */
+  sectionId: string | number;
+
+  /**
+   * 分类
+   */
+  categoryId: string | number;
+
+  /**
+   * 标题
+   */
+  title: string;
+
+  /**
+   * 子标题
+   */
+  subTitle: string;
+
+  /**
+   * 描述
+   */
+  description: string;
+
+  /**
+   * 封面
+   */
+  cover: string;
+
+  /**
+   * 内容
+   */
+  content: string;
+
+  /**
+   * 状态
+   */
+  status: string;
+
+  /**
+   * 是否置顶
+   */
+  top: string;
+
+  /**
+   * 浏览数
+   */
+  viewCount: number;
+
+  /**
+   * 点赞数
+   */
+  thumbupCount: number;
+
+  /**
+   * 收藏数
+   */
+  collectCount: number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId: string | number;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface ArticleForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 站点ID
+   */
+  siteId?: string | number;
+
+  /**
+   * 栏目id
+   */
+  sectionId?: string | number;
+
+  /**
+   * 分类
+   */
+  categoryId?: string | number;
+
+  /**
+   * 标题
+   */
+  title?: string;
+
+  /**
+   * 链接
+   */
+  link?: string;
+
+  /**
+   * 区域等级
+   */
+  areaLevel?: string;
+
+  /**
+   * 排序
+   */
+  sort?: number;
+
+  /**
+   * 手册
+   */
+  guide?: string;
+
+  /**
+   * 开始时间
+   */
+  startDate?: string;
+
+  /**
+   * 发布时间
+   */
+  publishDate?: string;
+
+  /**
+   * 结束时间
+   */
+  endDate?: string;
+
+  /**
+   * 有效期
+   */
+  validDate?: string;
+
+  /**
+ * 是否长期
+ */
+  validDateStatus?: string;
+
+  /**
+   * 子标题
+   */
+  subTitle?: string;
+
+  /**
+   * 描述
+   */
+  description?: string;
+
+  /**
+   * 封面
+   */
+  cover?: string;
+
+  /**
+   * 视频
+   */
+  video?: string;
+
+  /**
+   * 文件
+   */
+  accessorys?: string;
+
+  /**
+   * 内容
+   */
+  content?: string;
+
+  /**
+   * 状态
+   */
+  status?: string;
+
+  /**
+   * 内容状态
+   */
+  contentStatus?: string;
+
+  /**
+   * 发布单位
+   */
+  publisher?: string;
+
+  /**
+   * 是否置顶
+   */
+  top?: string;
+
+  /**
+   * 浏览数
+   */
+  viewCount?: number;
+
+  /**
+   * 点赞数
+   */
+  thumbupCount?: number;
+
+  /**
+   * 收藏数
+   */
+  collectCount?: number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+  config?: any;
+
+
+}
+
+export interface ArticleQuery extends PageQuery {
+
+  /**
+   * 站点ID
+   */
+  siteId?: string | number;
+
+  /**
+   * 栏目id
+   */
+  sectionId?: string | number;
+
+  /**
+   * 分类
+   */
+  categoryId?: string | number;
+
+  /**
+   * 标题
+   */
+  title?: string;
+
+  /**
+   * 子标题
+   */
+  subTitle?: string;
+
+  /**
+   * 描述
+   */
+  description?: string;
+
+  /**
+   * 封面
+   */
+  cover?: string;
+
+  /**
+   * 内容
+   */
+  content?: string;
+
+  /**
+   * 状态
+   */
+  status?: string;
+
+  /**
+   * 是否置顶
+   */
+  top?: string;
+
+  /**
+   * 浏览数
+   */
+  viewCount?: number;
+
+  /**
+   * 点赞数
+   */
+  thumbupCount?: number;
+
+  /**
+   * 收藏数
+   */
+  collectCount?: number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}
+
+
+

+ 63 - 0
src/api/smarttrace/category/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/smarttrace/category/types';
+
+/**
+ * 查询分类列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
+  return request({
+    url: '/smarttrace/category/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询分类详细
+ * @param id
+ */
+export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => {
+  return request({
+    url: '/smarttrace/category/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增分类
+ * @param data
+ */
+export const addCategory = (data: CategoryForm) => {
+  return request({
+    url: '/smarttrace/category/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改分类
+ * @param data
+ */
+export const updateCategory = (data: CategoryForm) => {
+  return request({
+    url: '/smarttrace/category/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除分类
+ * @param id
+ */
+export const delCategory = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/category/remove/' + id,
+    method: 'get'
+  });
+};

+ 146 - 0
src/api/smarttrace/category/types.ts

@@ -0,0 +1,146 @@
+export interface CategoryVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 站点ID
+   */
+  siteId: string | number;
+
+  /**
+   * 类别名称
+   */
+  name: string;
+
+  /**
+   * 类别类型
+   */
+  type: string;
+
+  /**
+   * 序号
+   */
+  sort: number;
+
+  /**
+   * 编号
+   */
+  sn: string;
+
+  /**
+   * 上级类别id
+   */
+  pid: string | number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId: string | number;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface CategoryForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 站点ID
+   */
+  siteId?: string | number;
+
+  /**
+   * 类别名称
+   */
+  name?: string;
+
+  /**
+   * 类别类型
+   */
+  type?: string;
+
+  /**
+   * 序号
+   */
+  sort?: number;
+
+  /**
+   * 编号
+   */
+  sn?: string;
+
+  /**
+   * 上级类别id
+   */
+  pid?: string | number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+}
+
+export interface CategoryQuery extends PageQuery {
+
+  /**
+   * 站点ID
+   */
+  siteId?: string | number;
+
+  /**
+   * 类别名称
+   */
+  name?: string;
+
+  /**
+   * 类别类型
+   */
+  type?: string;
+
+  /**
+   * 序号
+   */
+  sort?: number;
+
+  /**
+   * 编号
+   */
+  sn?: string;
+
+  /**
+   * 上级类别id
+   */
+  pid?: string | number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 76 - 0
src/api/smarttrace/companyCertificate/index.ts

@@ -0,0 +1,76 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CompanyCertificateVO, CompanyCertificateForm, CompanyCertificateQuery } from '@/api/smarttrace/companyCertificate/types';
+import { ApprovalForm } from '../companyFieldApply/types';
+
+/**
+ * 查询企业认证列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCompanyCertificate = (query?: CompanyCertificateQuery): AxiosPromise<CompanyCertificateVO[]> => {
+  return request({
+    url: '/companyCertificate/queryList',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询企业认证详细
+ * @param id
+ */
+export const getCompanyCertificate = (id: string | number): AxiosPromise<CompanyCertificateVO> => {
+  return request({
+    url: '/smarttrace/companyCertificate/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增企业认证
+ * @param data
+ */
+export const addCompanyCertificate = (data: CompanyCertificateForm) => {
+  return request({
+    url: '/smarttrace/companyCertificate/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改企业认证
+ * @param data
+ */
+export const updateCompanyCertificate = (data: CompanyCertificateForm) => {
+  return request({
+    url: '/smarttrace/companyCertificate/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除企业认证
+ * @param id
+ */
+export const delCompanyCertificate = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/companyCertificate/remove/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 审批企业认证
+ * @param id
+ */
+export const approvalCert = (data:ApprovalForm) => {
+  return request({
+    url: '/approval/approvalCert',
+    method: 'post',
+    data
+  });
+};

+ 191 - 0
src/api/smarttrace/companyCertificate/types.ts

@@ -0,0 +1,191 @@
+export interface CompanyCertificateVO {
+    /**
+     * ID
+     */
+    id: string | number;
+
+    /**
+     * 企业ID
+     */
+    cpyid: string | number;
+
+    /**
+     * 认证类型
+     */
+    cpyType: string;
+
+    /**
+     * 认证材料
+     */
+    certMaterials: any;
+
+    /**
+     * 审核结果
+     */
+    res: string;
+
+    /**
+     * 创建人
+     */
+    createBy: string;
+
+    /**
+     * 创建时间
+     */
+    createTime: string;
+
+    /**
+     * 更新时间
+     */
+    updateTime: string;
+
+    /**
+     * 行业类别
+     */
+    industryType: string;
+
+    /**
+     * 审核人
+     */
+    auditor: number;
+
+    /**
+     * 申请人
+     */
+    applyer: number;
+
+    /**
+     * 审核时间
+     */
+    auditorTime: string;
+
+    /**
+     * 说明
+     */
+    msg: string;
+
+    /**
+     * 认证类型:基础、特殊
+     */
+    certType: string;
+}
+
+export interface CompanyCertificateForm extends BaseEntity {
+    /**
+     * ID
+     */
+    id?: string | number;
+
+    /**
+     * 企业ID
+     */
+    cpyid?: string | number;
+
+    /**
+     * 认证类型
+     */
+    cpyType?: string;
+
+    /**
+     * 认证材料
+     */
+    certMaterials?: any[];
+
+    /**
+     * 审核结果
+     */
+    res?: string;
+
+    /**
+     * 行业类别
+     */
+    industryType?: string;
+
+    /**
+     * 审核人
+     */
+    auditor?: number;
+
+    /**
+     * 申请人
+     */
+    applyer?: number;
+
+    /**
+     * 审核时间
+     */
+    auditorTime?: string;
+
+    /**
+     * 说明
+     */
+    msg?: string;
+
+    /**
+     * 认证类型:基础、特殊
+     */
+    certType?: string;
+
+    specialCertMaterials: any;
+
+    specialType?:string;
+}
+
+export interface CompanyCertificateQuery extends PageQuery {
+    /**
+     * 企业ID
+     */
+    cpyid?: string | number;
+
+    /**
+     * 认证类型
+     */
+    cpyType?: string;
+
+    /**
+     * 认证材料
+     */
+    certMaterials?: string;
+
+    /**
+     * 审核结果
+     */
+    res?: string;
+
+    /**
+     * 行业类别
+     */
+    industryType?: string;
+
+    /**
+     * 审核人
+     */
+    auditor?: number;
+
+    /**
+     * 申请人
+     */
+    applyer?: number;
+
+    /**
+     * 审核时间
+     */
+    auditorTime?: string;
+
+    /**
+     * 说明
+     */
+    msg?: string;
+
+    /**
+     * 认证类型:基础、特殊
+     */
+    certType?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+
+    cpyName?: string;
+}

+ 85 - 0
src/api/smarttrace/companyFieldApply/index.ts

@@ -0,0 +1,85 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CompanyFieldApplyVO, CompanyFieldApplyForm, CompanyFieldApplyQuery, ApprovalForm } from '@/api/smarttrace/companyFieldApply/types';
+
+/**
+ * 查询企业字段修改申请列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCompanyFieldApply = (query?: CompanyFieldApplyQuery): AxiosPromise<CompanyFieldApplyVO[]> => {
+    return request({
+        url: '/smarttrace/companyFieldApply/list',
+        method: 'get',
+        params: query
+    });
+};
+
+/**
+ * 查询企业字段修改申请详细
+ * @param id
+ */
+export const getCompanyFieldApply = (id: string | number): AxiosPromise<CompanyFieldApplyVO> => {
+    return request({
+        url: '/smarttrace/companyFieldApply/getInfo/' + id,
+        method: 'get'
+    });
+};
+
+/**
+ * 新增企业字段修改申请
+ * @param data
+ */
+export const addCompanyFieldApply = (data: CompanyFieldApplyForm) => {
+    return request({
+        url: '/smarttrace/companyFieldApply/add',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 修改企业字段修改申请
+ * @param data
+ */
+export const updateCompanyFieldApply = (data: CompanyFieldApplyForm) => {
+    return request({
+        url: '/smarttrace/companyFieldApply/edit',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 删除企业字段修改申请
+ * @param id
+ */
+export const delCompanyFieldApply = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/smarttrace/companyFieldApply/remove/' + id,
+        method: 'get'
+    });
+};
+/**
+ * 查询申请
+ * @param id
+ */
+export const listByPage = (query?: CompanyFieldApplyQuery) => {
+    return request({
+        url: '/smarttrace/companyFieldApply/listByPage',
+        method: 'get',
+        params:query
+    });
+};
+/**
+ * 删除企业字段修改申请
+ * @param id
+ */
+export const approvalCpyField = (data?: ApprovalForm) => {
+  return request({
+      url: '/approval/approvalCpyField',
+      method: 'post',
+      data
+  });
+};

+ 195 - 0
src/api/smarttrace/companyFieldApply/types.ts

@@ -0,0 +1,195 @@
+export interface CompanyFieldApplyVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 企业ID
+   */
+  cpyid: string | number;
+
+  /**
+   * 字段
+   */
+  field: string;
+
+  /**
+   * 字段值
+   */
+  fieldValue: string;
+
+  /**
+   * 审核人
+   */
+  auditor: number;
+
+  /**
+   * 申请人
+   */
+  applyer: number;
+
+  /**
+   * 审核时间
+   */
+  auditorTime: string;
+
+  /**
+   * 结果
+   */
+  res: string;
+
+  /**
+   * 说明
+   */
+  msg: string;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId: string | number;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface CompanyFieldApplyForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 企业ID
+   */
+  cpyid?: string | number;
+
+  /**
+   * 字段
+   */
+  field?: string;
+
+  /**
+   * 字段值
+   */
+  fieldValue?: string;
+
+  /**
+   * 审核人
+   */
+  auditor?: number;
+
+  /**
+   * 申请人
+   */
+  applyer?: number;
+
+  /**
+   * 审核时间
+   */
+  auditorTime?: string;
+
+  /**
+   * 结果
+   */
+  res?: string;
+
+  /**
+   * 说明
+   */
+  msg?: string;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+}
+
+export interface CompanyFieldApplyQuery extends PageQuery {
+
+  /**
+   * 企业ID
+   */
+  cpyid?: string | number;
+
+  /**
+   * 字段
+   */
+  field?: string;
+
+  /**
+   * 字段值
+   */
+  fieldValue?: string;
+
+  /**
+   * 审核人
+   */
+  auditor?: number;
+
+  /**
+   * 申请人
+   */
+  applyer?: number;
+
+  /**
+   * 审核时间
+   */
+  auditorTime?: string;
+
+  /**
+   * 结果
+   */
+  res?: string;
+
+  /**
+   * 说明
+   */
+  msg?: string;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+/**
+ * ApprovalLogBo,审核日志业务对象 st_approval_log
+ */
+export interface ApprovalForm {
+  /**
+   * 说明
+   */
+  msg?: string;
+  /**
+   * 结果
+   */
+  res: string;
+  /**
+   * 目标id
+   */
+  targetId?: number|string;
+  /**
+   * 目标类型(备案审核cpy,应用app,认证cert,企业字段field)
+   */
+  targetType: string;
+}

+ 63 - 0
src/api/smarttrace/dataEnterprise/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { DataEnterpriseVO, DataEnterpriseForm, DataEnterpriseQuery } from '@/api/smarttrace/dataEnterprise/types';
+
+/**
+ * 查询企业展示列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listDataEnterprise = (query?: DataEnterpriseQuery): AxiosPromise<DataEnterpriseVO[]> => {
+  return request({
+    url: '/smarttrace/dataEnterprise/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询企业展示详细
+ * @param id
+ */
+export const getDataEnterprise = (id: string | number): AxiosPromise<DataEnterpriseVO> => {
+  return request({
+    url: '/smarttrace/dataEnterprise/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增企业展示
+ * @param data
+ */
+export const addDataEnterprise = (data: DataEnterpriseForm) => {
+  return request({
+    url: '/smarttrace/dataEnterprise/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改企业展示
+ * @param data
+ */
+export const updateDataEnterprise = (data: DataEnterpriseForm) => {
+  return request({
+    url: '/smarttrace/dataEnterprise/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除企业展示
+ * @param id
+ */
+export const delDataEnterprise = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/dataEnterprise/remove/' + id,
+    method: 'get'
+  });
+};

+ 151 - 0
src/api/smarttrace/dataEnterprise/types.ts

@@ -0,0 +1,151 @@
+export interface DataEnterpriseVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 企业名称
+   */
+  enName: string;
+
+  /**
+   * 主营产品
+   */
+  product: string;
+
+  /**
+   * 地区
+   */
+  area: string;
+
+  /**
+   * 联系人
+   */
+  contact: string;
+
+  /**
+   * 联系电话
+   */
+  phone: string;
+
+  /**
+   * 上传日期
+   */
+  uploadDate: string;
+
+  /**
+   * 图片
+   */
+  pic: string;
+
+  /**
+   * 宣传标语
+   */
+  slogan: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface DataEnterpriseForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 企业名称
+   */
+  enName?: string;
+
+  /**
+   * 主营产品
+   */
+  product?: string;
+
+  /**
+   * 地区
+   */
+  area?: string;
+
+  /**
+   * 联系人
+   */
+  contact?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 上传日期
+   */
+  uploadDate?: string;
+
+  /**
+   * 图片
+   */
+  pic?: string;
+
+  /**
+   * 宣传标语
+   */
+  slogan?: string;
+
+}
+
+export interface DataEnterpriseQuery extends PageQuery {
+
+  /**
+   * 企业名称
+   */
+  enName?: string;
+
+  /**
+   * 主营产品
+   */
+  product?: string;
+
+  /**
+   * 地区
+   */
+  area?: string;
+
+  /**
+   * 联系人
+   */
+  contact?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 上传日期
+   */
+  uploadDate?: string;
+
+  /**
+   * 图片
+   */
+  pic?: string;
+
+  /**
+   * 宣传标语
+   */
+  slogan?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 63 - 0
src/api/smarttrace/dataHonor/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { DataHonorVO, DataHonorForm, DataHonorQuery } from '@/api/smarttrace/dataHonor/types';
+
+/**
+ * 查询荣誉墙列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listDataHonor = (query?: DataHonorQuery): AxiosPromise<DataHonorVO[]> => {
+  return request({
+    url: '/smarttrace/dataHonor/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询荣誉墙详细
+ * @param id
+ */
+export const getDataHonor = (id: string | number): AxiosPromise<DataHonorVO> => {
+  return request({
+    url: '/smarttrace/dataHonor/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增荣誉墙
+ * @param data
+ */
+export const addDataHonor = (data: DataHonorForm) => {
+  return request({
+    url: '/smarttrace/dataHonor/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改荣誉墙
+ * @param data
+ */
+export const updateDataHonor = (data: DataHonorForm) => {
+  return request({
+    url: '/smarttrace/dataHonor/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除荣誉墙
+ * @param id
+ */
+export const delDataHonor = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/dataHonor/remove/' + id,
+    method: 'get'
+  });
+};

+ 91 - 0
src/api/smarttrace/dataHonor/types.ts

@@ -0,0 +1,91 @@
+export interface DataHonorVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 年份
+   */
+  year: number;
+
+  /**
+   * 标题
+   */
+  title: string;
+
+  /**
+   * 图片
+   */
+  pic: string;
+
+  /**
+   * 排序
+   */
+  sort: number;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface DataHonorForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 年份
+   */
+  year?: any;
+
+  /**
+   * 标题
+   */
+  title?: string;
+
+  /**
+   * 图片
+   */
+  pic?: string;
+
+  /**
+   * 排序
+   */
+  sort?: number;
+
+}
+
+export interface DataHonorQuery extends PageQuery {
+
+  /**
+   * 年份
+   */
+  year?: number;
+
+  /**
+   * 标题
+   */
+  title?: string;
+
+  /**
+   * 图片
+   */
+  pic?: string;
+
+  /**
+   * 排序
+   */
+  sort?: number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 63 - 0
src/api/smarttrace/dataProduct/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { DataProductVO, DataProductForm, DataProductQuery } from '@/api/smarttrace/dataProduct/types';
+
+/**
+ * 查询产品展示列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listDataProduct = (query?: DataProductQuery): AxiosPromise<DataProductVO[]> => {
+  return request({
+    url: '/smarttrace/dataProduct/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品展示详细
+ * @param id
+ */
+export const getDataProduct = (id: string | number): AxiosPromise<DataProductVO> => {
+  return request({
+    url: '/smarttrace/dataProduct/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品展示
+ * @param data
+ */
+export const addDataProduct = (data: DataProductForm) => {
+  return request({
+    url: '/smarttrace/dataProduct/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品展示
+ * @param data
+ */
+export const updateDataProduct = (data: DataProductForm) => {
+  return request({
+    url: '/smarttrace/dataProduct/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除产品展示
+ * @param id
+ */
+export const delDataProduct = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/dataProduct/remove/' + id,
+    method: 'get'
+  });
+};

+ 181 - 0
src/api/smarttrace/dataProduct/types.ts

@@ -0,0 +1,181 @@
+export interface DataProductVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 品种名称
+   */
+  productName: string;
+
+  /**
+   * 规格
+   */
+  spec: string;
+
+  /**
+   * 类型
+   */
+  type: string;
+
+  /**
+   * 产地
+   */
+  area: string;
+
+  /**
+   * 行政区划代码
+   */
+  adcode: string;
+
+  /**
+   * 溯源码
+   */
+  traceCode: string;
+
+  /**
+   * 图片
+   */
+  pic: string;
+
+  /**
+   * 生产厂家
+   */
+  manufacturer: string;
+
+  /**
+   * 联系人
+   */
+  contact: string;
+
+  /**
+   * 联系电话
+   */
+  phone: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface DataProductForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 品种名称
+   */
+  productName?: string;
+
+  /**
+   * 规格
+   */
+  spec?: string;
+
+  /**
+   * 类型
+   */
+  type?: string;
+
+  /**
+   * 产地
+   */
+  area?: string;
+
+  /**
+   * 行政区划代码
+   */
+  adcode?: string;
+
+  /**
+   * 溯源码
+   */
+  traceCode?: string;
+
+  /**
+   * 图片
+   */
+  pic?: string;
+
+  /**
+   * 生产厂家
+   */
+  manufacturer?: string;
+
+  /**
+   * 联系人
+   */
+  contact?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+}
+
+export interface DataProductQuery extends PageQuery {
+
+  /**
+   * 品种名称
+   */
+  productName?: string;
+
+  /**
+   * 规格
+   */
+  spec?: string;
+
+  /**
+   * 类型
+   */
+  type?: string;
+
+  /**
+   * 产地
+   */
+  area?: string;
+
+  /**
+   * 行政区划代码
+   */
+  adcode?: string;
+
+  /**
+   * 溯源码
+   */
+  traceCode?: string;
+
+  /**
+   * 图片
+   */
+  pic?: string;
+
+  /**
+   * 生产厂家
+   */
+  manufacturer?: string;
+
+  /**
+   * 联系人
+   */
+  contact?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 72 - 0
src/api/smarttrace/geoIdentityApply/index.ts

@@ -0,0 +1,72 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { GeoIdentityApplyVO, GeoIdentityApplyForm, GeoIdentityApplyQuery } from '@/api/smarttrace/geoIdentityApply/types';
+
+/**
+ * 查询地址标志申报列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listGeoIdentityApply = (query?: GeoIdentityApplyQuery): AxiosPromise<GeoIdentityApplyVO[]> => {
+  return request({
+    url: '/smarttrace/geoIdentityApply/queryPageList',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询地址标志申报详细
+ * @param id
+ */
+export const getGeoIdentityApply = (id: string | number): AxiosPromise<GeoIdentityApplyVO> => {
+  return request({
+    url: '/smarttrace/geoIdentityApply/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增地址标志申报
+ * @param data
+ */
+export const addGeoIdentityApply = (data: GeoIdentityApplyForm) => {
+  return request({
+    url: '/smarttrace/geoIdentityApply/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改地址标志申报
+ * @param data
+ */
+export const updateGeoIdentityApply = (data: GeoIdentityApplyForm) => {
+  return request({
+    url: '/smarttrace/geoIdentityApply/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除地址标志申报
+ * @param id
+ */
+export const delGeoIdentityApply = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/geoIdentityApply/remove/' + id,
+    method: 'get'
+  });
+};
+
+// 基地申报审批
+export const geoApproval = (query?: any): AxiosPromise<any> => {
+  return request({
+      url: '/smarttrace/geoIdentityApply/approval',
+      method: 'post',
+      data: query
+  });
+};

+ 331 - 0
src/api/smarttrace/geoIdentityApply/types.ts

@@ -0,0 +1,331 @@
+export interface GeoIdentityApplyVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 经营组织简介
+   */
+  orgSummary: string;
+
+  /**
+   * 品牌LOGO申请书
+   */
+  brandLogoApply: string;
+
+  /**
+   * 营业执照
+   */
+  bizLicence: string;
+
+  /**
+   * 法人代表身份证
+   */
+  leageRpstIdCard: string | number;
+
+  /**
+   * 合同
+   */
+  contract: string;
+
+  /**
+   * 样品图片
+   */
+  samplePic: string;
+
+  /**
+   * 产品图片
+   */
+  productPic: string;
+
+  /**
+   * 生产许可证
+   */
+  produceLicense: string;
+
+  /**
+   * 商标申请书
+   */
+  bizApply: string;
+
+  /**
+   * 续签申请书
+   */
+  renewalApply: string;
+
+  /**
+   * 注销申请书
+   */
+  offApply: string;
+
+  /**
+   * 业务类别
+   */
+  bizType: string;
+
+  /**
+   * 申请类别
+   */
+  applyType: string;
+
+  /**
+   * 申请状态
+   */
+  applyStatus: string;
+
+  /**
+   * 审核时间
+   */
+  approveTime: string;
+
+  /**
+   * 审核人
+   */
+  approveBy: string;
+
+  /**
+   * 审核备注
+   */
+  approveRemark: string;
+
+  /**
+   * 企业ID
+   */
+  cpyid: string | number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId: string | number;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface GeoIdentityApplyForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 经营组织简介
+   */
+  orgSummary?: string;
+
+  /**
+   * 品牌LOGO申请书
+   */
+  brandLogoApply?: string;
+
+  /**
+   * 营业执照
+   */
+  bizLicence?: any;
+
+  /**
+   * 法人代表身份证
+   */
+  leageRpstIdCard?: any;
+
+  /**
+   * 合同
+   */
+  contract?: any;
+
+  /**
+   * 样品图片
+   */
+  samplePic?: any;
+
+  /**
+   * 产品图片
+   */
+  productPic?: any;
+
+  /**
+   * 生产许可证
+   */
+  produceLicense?: any;
+
+  /**
+   * 商标申请书
+   */
+  bizApply?: any;
+
+  /**
+   * 续签申请书
+   */
+  renewalApply?: any;
+
+  /**
+   * 注销申请书
+   */
+  offApply?: any;
+
+  /**
+   * 业务类别
+   */
+  bizType?: string;
+
+  /**
+   * 申请类别
+   */
+  applyType?: string;
+
+  /**
+   * 申请状态
+   */
+  applyStatus?: string;
+
+  /**
+   * 审核时间
+   */
+  approveTime?: string;
+
+  /**
+   * 审核人
+   */
+  approveBy?: string;
+
+  /**
+   * 审核备注
+   */
+  approveRemark?: string;
+
+  /**
+   * 企业ID
+   */
+  cpyid?: string | number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+}
+
+export interface GeoIdentityApplyQuery extends PageQuery {
+
+  /**
+   * 经营组织简介
+   */
+  orgSummary?: string;
+
+  /**
+   * 品牌LOGO申请书
+   */
+  brandLogoApply?: string;
+
+  /**
+   * 营业执照
+   */
+  bizLicence?: string;
+
+  /**
+   * 法人代表身份证
+   */
+  leageRpstIdCard?: string | number;
+
+  /**
+   * 合同
+   */
+  contract?: string;
+
+  /**
+   * 样品图片
+   */
+  samplePic?: string;
+
+  /**
+   * 产品图片
+   */
+  productPic?: string;
+
+  /**
+   * 生产许可证
+   */
+  produceLicense?: string;
+
+  /**
+   * 商标申请书
+   */
+  bizApply?: string;
+
+  /**
+   * 续签申请书
+   */
+  renewalApply?: string;
+
+  /**
+   * 注销申请书
+   */
+  offApply?: string;
+
+  /**
+   * 业务类别
+   */
+  bizType?: string;
+
+  /**
+   * 申请类别
+   */
+  applyType?: string;
+
+  /**
+   * 申请状态
+   */
+  applyStatus?: string;
+
+  /**
+   * 审核时间
+   */
+  approveTime?: string;
+
+  /**
+   * 审核人
+   */
+  approveBy?: string;
+
+  /**
+   * 审核备注
+   */
+  approveRemark?: string;
+
+  /**
+   * 企业ID
+   */
+  cpyid?: string | number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+
+  /**
+   * 关键字
+   */
+  keywords?: string;
+}
+
+
+

+ 63 - 0
src/api/smarttrace/section/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { SectionVO, SectionForm, SectionQuery } from '@/api/smarttrace/section/types';
+
+/**
+ * 查询栏目列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSection = (query?: SectionQuery): AxiosPromise<SectionVO[]> => {
+  return request({
+    url: '/smarttrace/section/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询栏目详细
+ * @param id
+ */
+export const getSection = (id: string | number): AxiosPromise<SectionVO> => {
+  return request({
+    url: '/smarttrace/section/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增栏目
+ * @param data
+ */
+export const addSection = (data: SectionForm) => {
+  return request({
+    url: '/smarttrace/section/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改栏目
+ * @param data
+ */
+export const updateSection = (data: SectionForm) => {
+  return request({
+    url: '/smarttrace/section/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除栏目
+ * @param id
+ */
+export const delSection = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/section/remove/' + id,
+    method: 'get'
+  });
+};

+ 176 - 0
src/api/smarttrace/section/types.ts

@@ -0,0 +1,176 @@
+export interface SectionVO {
+  /**
+   * ID
+   */
+  id: string | number;
+
+  /**
+   * 站点ID
+   */
+  siteId: string | number;
+
+  /**
+   * 上级id
+   */
+  pid: string | number;
+
+  /**
+   * 标题
+   */
+  title: string;
+
+  /**
+   * 序号
+   */
+  sort: number;
+
+  /**
+   * 图标
+   */
+  icon: string;
+
+  /**
+   * 页面路径
+   */
+  page: string;
+
+  /**
+   * 页面参数
+   */
+  params: string;
+
+  /**
+   * 级别
+   */
+  level: number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId: string | number;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface SectionForm extends BaseEntity {
+  /**
+   * ID
+   */
+  id?: string | number;
+
+  /**
+   * 站点ID
+   */
+  siteId?: string | number;
+
+  /**
+   * 上级id
+   */
+  pid?: string | number;
+
+  /**
+   * 标题
+   */
+  title?: string;
+
+  /**
+   * 序号
+   */
+  sort?: number;
+
+  /**
+   * 图标
+   */
+  icon?: string;
+
+  /**
+   * 页面路径
+   */
+  page?: string;
+
+  /**
+   * 页面参数
+   */
+  param?: string;
+
+  /**
+   * 级别
+   */
+  level?: number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+}
+
+export interface SectionQuery extends PageQuery {
+
+  /**
+   * 站点ID
+   */
+  siteId?: string | number;
+
+  /**
+   * 上级id
+   */
+  pid?: string | number;
+
+  /**
+   * 标题
+   */
+  title?: string;
+
+  /**
+   * 序号
+   */
+  sort?: number;
+
+  /**
+   * 图标
+   */
+  icon?: string;
+
+  /**
+   * 页面路径
+   */
+  page?: string;
+
+  /**
+   * 页面参数
+   */
+  param?: string;
+
+  /**
+   * 级别
+   */
+  level?: number;
+
+  /**
+   * 合作伙伴ID
+   */
+  partnerId?: string | number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 74 - 0
src/api/smarttrace/site/index.ts

@@ -0,0 +1,74 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { SiteVO, SiteForm, SiteQuery } from '@/api/smarttrace/site/types';
+
+/**
+ * 查询站点列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSite = (query?: SiteQuery): AxiosPromise<SiteVO[]> => {
+  return request({
+    url: '/smarttrace/site/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询站点详细
+ * @param id
+ */
+export const getSite = (id: string | number): AxiosPromise<SiteVO> => {
+  return request({
+    url: '/smarttrace/site/getInfo/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增站点
+ * @param data
+ */
+export const addSite = (data: SiteForm) => {
+  return request({
+    url: '/smarttrace/site/add',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改站点
+ * @param data
+ */
+export const updateSite = (data: SiteForm) => {
+  return request({
+    url: '/smarttrace/site/edit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 删除站点
+ * @param id
+ */
+export const delSite = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/smarttrace/site/remove/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ *
+ * @returns 站点下拉
+ */
+export const getDeptSite = () => {
+  return request({
+    url: '/smarttrace/site/getDeptSite',
+    method: 'get'
+  });
+}

+ 131 - 0
src/api/smarttrace/site/types.ts

@@ -0,0 +1,131 @@
+export interface SiteVO {
+  /**
+   * 站点ID
+   */
+  id: string | number;
+
+  /**
+   * 站点名称
+   */
+  name: string;
+
+  /**
+   * 简介
+   */
+  description: string;
+
+  /**
+   * 站点LOGO
+   */
+  logo: string;
+
+  /**
+   * 首页路由
+   */
+  indexTemplate: string;
+
+  /**
+   * 排序标识
+   */
+  sortFlag: number;
+
+  /**
+   * 站点扩展属性
+   */
+  configProps: string;
+
+  /**
+   * 创建人
+   */
+  createBy: string;
+
+  /**
+   * 创建时间
+   */
+  createTime: string;
+
+  /**
+   * 更新时间
+   */
+  updateTime: string;
+
+}
+
+export interface SiteForm extends BaseEntity {
+  /**
+   * 站点ID
+   */
+  id?: string | number;
+
+  /**
+   * 站点名称
+   */
+  name?: string;
+
+  /**
+   * 简介
+   */
+  description?: string;
+
+  /**
+   * 站点LOGO
+   */
+  logo?: string;
+
+  /**
+   * 首页路由
+   */
+  indexTemplate?: string;
+
+  /**
+   * 排序标识
+   */
+  sortFlag?: number;
+
+  /**
+   * 站点扩展属性
+   */
+  configProps?: string;
+
+}
+
+export interface SiteQuery extends PageQuery {
+
+  /**
+   * 站点名称
+   */
+  name?: string;
+
+  /**
+   * 简介
+   */
+  description?: string;
+
+  /**
+   * 站点LOGO
+   */
+  logo?: string;
+
+  /**
+   * 首页路由
+   */
+  indexTemplate?: string;
+
+  /**
+   * 排序标识
+   */
+  sortFlag?: number;
+
+  /**
+   * 站点扩展属性
+   */
+  configProps?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

BIN
src/assets/images/cloud.png


BIN
src/assets/images/cpy_sld.png


BIN
src/assets/images/cpy_slx.png


+ 39 - 0
src/assets/images/dark copy.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
+            <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                    <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
src/assets/images/earth_bg.png


BIN
src/assets/images/ground.png


BIN
src/assets/images/icon_pic.png


BIN
src/assets/images/login.gif


BIN
src/assets/images/login_border.png


BIN
src/assets/images/login_horizontal_line.png


BIN
src/assets/images/login_human.png


BIN
src/assets/images/nodata.jpg


BIN
src/assets/images/sky.png


BIN
src/assets/images/starflake1.png


BIN
src/assets/images/starflake2.png


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/a_icon.svg


+ 6 - 0
src/assets/svg/back_icon.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="17px" height="11px" xmlns="http://www.w3.org/2000/svg">
+  <g transform="matrix(1 0 0 1 -262 -83 )">
+    <path d="M 9.661114516173251 5.697702703993055  L 2.9613707776305236 5.697718811770979  L 5.654372173850577 8.463583333333334  L 4.579215893678151 9.567943701822912  L 0.016308178160924867 4.881349103841145  L 4.579215893678151 0.19440765494791604  L 5.654034176724141 1.298768023437499  L 2.81864409258054 4.211216223958333  L 9.661114516173251 4.211216223958333  C 13.635551695038387 4.211216223958333  16.85737815515351 7.218543559027778  16.857378129523024 10.920225221354166  L 15.261361066748893 10.920225221354166  C 15.261361066748893 8.039744739583332  12.753840902549355 5.697702703993055  9.661114516173251 5.697702703993055  Z " fill-rule="nonzero" fill="#676767" stroke="none" transform="matrix(1 0 0 1 262 83 )" />
+  </g>
+</svg>

File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/check_card_icon.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/ck_icon.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/clear_icon.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/delete_icon.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/dw_icon.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/edit_icon.svg


File diff suppressed because it is too large
+ 8 - 0
src/assets/svg/land_bg.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/land_icon.svg


+ 6 - 0
src/assets/svg/log_icon.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="20px" height="20px" xmlns="http://www.w3.org/2000/svg">
+  <g transform="matrix(1 0 0 1 -787 -14 )">
+    <path d="M 19.09125 20  L 9.591249999999999 20  C 9.094193725152284 20  8.691249999999998 19.597056274847713  8.691249999999998 19.099999999999998  C 8.691249999999998 18.602943725152283  9.094193725152284 18.2  9.591249999999999 18.2  L 19.09125 18.2  C 19.588306274847714 18.2  19.99125 18.602943725152283  19.99125 19.099999999999998  C 19.99125 19.597056274847713  19.588306274847714 20  19.09125 20  Z M 15.668 2.4819999999999993  L 17.5065 4.3205  L 4.33475 17.49225  L 2.1319999999999997 17.869750000000003  L 2.5 15.649999999999999  L 15.668 2.4819999999999993  Z M 19.770249999999997 4.036999999999998  L 19.76925 4.03775  L 15.95 0.2192499999999999  C 15.793811516285722 0.06316385942553353  15.54068848371428 0.06316385942553175  15.384500000000001 0.2192499999999999  L 1.0124999999999993 14.591999999999999  C 0.8868444853522626 14.718086903355804  0.8037968914174229 14.8803356763485  0.775 15.055999999999997  L 0.12624999999999992 18.96175  C 0.11905068859667942 19.00508331410643  0.11543268734993717 19.04893597328668  0.11543268734993717 19.092863256336383  C 0.11543268734993717 19.53469105620102  0.4736048874853026 19.892863256336383  0.9154326873499372 19.892863256336383  C 0.960953075298915 19.892863256336383  1.0063904119682519 19.888978070952522  1.0512500000000002 19.881249999999998  L 4.9357500000000005 19.21575  C 5.10982372935986 19.18578514631415  5.270344554151379 19.102642695170776  5.395250000000001 18.977749999999997  L 19.770249999999997 4.602749999999998  C 19.845284304882114 4.527732825018493  19.887439578736917 4.42597741963003  19.887439578736917 4.319874999999998  C 19.887439578736917 4.213772580369966  19.84528430488211 4.112017174981501  19.770249999999997 4.036999999999998  Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 787 14 )" />
+  </g>
+</svg>

File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/look_icon.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/no_pass_icon.svg


+ 6 - 0
src/assets/svg/normal_u143.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="1321px" height="2px" xmlns="http://www.w3.org/2000/svg">
+  <g transform="matrix(1 0 0 1 -22 -201 )">
+    <path d="M 22 201.5  L 1342 201.5  " stroke-width="1" stroke="#e4e4e4" fill="none" />
+  </g>
+</svg>

+ 6 - 0
src/assets/svg/normal_u190.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" xmlns="http://www.w3.org/2000/svg">
+  <g transform="matrix(1 0 0 1 -186 -422 )">
+    <path d="M 15.75 13.54639175257732  C 15.75 12.931701030927835  16.25390625 12.43298969072165  16.875 12.43298969072165  C 17.49609375 12.43298969072165  18 12.931701030927835  18 13.54639175257732  L 18 15.302319587628862  C 18 16.789175257731962  16.72265625 18  15.15234375 18  L 2.84765625 18  C 1.27734375 18  0 16.789175257731962  0 15.302319587628862  L 0 13.54639175257732  C 0 12.931701030927835  0.50390625 12.43298969072165  1.125 12.43298969072165  C 1.74609375 12.43298969072165  2.25 12.931701030927835  2.25 13.54639175257732  L 2.25 15.302319587628862  C 2.25 15.557474226804121  2.5242187499999957 15.77319587628866  2.84765625 15.77319587628866  L 15.15234375 15.77319587628866  C 15.475781250000004 15.77319587628866  15.75 15.557474226804121  15.75 15.302319587628862  L 15.75 13.54639175257732  Z M 10.931249999999991 4.780670103092781  L 10.125 3.9845895016763033  L 10.125 12.0201030927835  C 10.125 12.634793814432985  9.62109375 13.13350515463917  9 13.13350515463917  C 8.37890625 13.13350515463917  7.875 12.634793814432985  7.875 12.0201030927835  L 7.875041749132791 3.987329815291266  L 7.071093749999996 4.78298969072165  C 6.6304687499999915 5.219072164948454  5.9203125000000085 5.219072164948454  5.479687500000004 4.78298969072165  C 5.0390625 4.346907216494848  5.0390625 3.6440721649484518  5.479687500000004 3.2079896907216487  L 8.205468750000009 0.5103092783505154  C 8.646093749999991 0.07422680412371238  9.356249999999996 0.07422680412371238  9.796875 0.5103092783505154  L 12.522656250000004 3.2079896907216487  C 12.963281250000009 3.6440721649484518  12.963281250000009 4.346907216494848  12.522656250000004 4.78298969072165  C 12.300000000000004 5.00103092783505  12.01171875 5.107731958762887  11.725781250000004 5.107731958762887  C 11.4375 5.107731958762887  11.149218749999996 4.998711340206186  10.931249999999991 4.780670103092781  Z " fill-rule="nonzero" fill="#0f8240" stroke="none" transform="matrix(1 0 0 1 186 422 )" />
+  </g>
+</svg>

File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/normal_u191.svg


File diff suppressed because it is too large
+ 10 - 0
src/assets/svg/normal_u27.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/normal_u55.svg


File diff suppressed because it is too large
+ 3 - 0
src/assets/svg/pass_icon.svg


+ 6 - 0
src/assets/svg/uplod_icon.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" xmlns="http://www.w3.org/2000/svg">
+  <g transform="matrix(1 0 0 1 -140 -714 )">
+    <path d="M 15.75 13.54639175257732  C 15.75 12.931701030927835  16.25390625 12.43298969072165  16.875 12.43298969072165  C 17.49609375 12.43298969072165  18 12.931701030927835  18 13.54639175257732  L 18 15.302319587628862  C 18 16.789175257731962  16.72265625 18  15.15234375 18  L 2.84765625 18  C 1.27734375 18  0 16.789175257731962  0 15.302319587628862  L 0 13.54639175257732  C 0 12.931701030927835  0.50390625 12.43298969072165  1.125 12.43298969072165  C 1.74609375 12.43298969072165  2.25 12.931701030927835  2.25 13.54639175257732  L 2.25 15.302319587628862  C 2.25 15.557474226804121  2.5242187499999957 15.77319587628866  2.84765625 15.77319587628866  L 15.15234375 15.77319587628866  C 15.475781250000004 15.77319587628866  15.75 15.557474226804121  15.75 15.302319587628862  L 15.75 13.54639175257732  Z M 10.931249999999991 4.780670103092781  L 10.125 3.9845895016763033  L 10.125 12.0201030927835  C 10.125 12.634793814432985  9.62109375 13.13350515463917  9 13.13350515463917  C 8.37890625 13.13350515463917  7.875 12.634793814432985  7.875 12.0201030927835  L 7.875041749132791 3.987329815291266  L 7.071093749999996 4.78298969072165  C 6.6304687499999915 5.219072164948454  5.9203125000000085 5.219072164948454  5.479687500000004 4.78298969072165  C 5.0390625 4.346907216494848  5.0390625 3.6440721649484518  5.479687500000004 3.2079896907216487  L 8.205468750000009 0.5103092783505154  C 8.646093749999991 0.07422680412371238  9.356249999999996 0.07422680412371238  9.796875 0.5103092783505154  L 12.522656250000004 3.2079896907216487  C 12.963281250000009 3.6440721649484518  12.963281250000009 4.346907216494848  12.522656250000004 4.78298969072165  C 12.300000000000004 5.00103092783505  12.01171875 5.107731958762887  11.725781250000004 5.107731958762887  C 11.4375 5.107731958762887  11.149218749999996 4.998711340206186  10.931249999999991 4.780670103092781  Z " fill-rule="nonzero" fill="#0f8240" stroke="none" transform="matrix(1 0 0 1 140 714 )" />
+  </g>
+</svg>

+ 6 - 0
src/assets/svg/uploud_icon.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="18px" height="18px" xmlns="http://www.w3.org/2000/svg">
+  <g transform="matrix(1 0 0 1 -186 -422 )">
+    <path d="M 15.75 13.54639175257732  C 15.75 12.931701030927835  16.25390625 12.43298969072165  16.875 12.43298969072165  C 17.49609375 12.43298969072165  18 12.931701030927835  18 13.54639175257732  L 18 15.302319587628862  C 18 16.789175257731962  16.72265625 18  15.15234375 18  L 2.84765625 18  C 1.27734375 18  0 16.789175257731962  0 15.302319587628862  L 0 13.54639175257732  C 0 12.931701030927835  0.50390625 12.43298969072165  1.125 12.43298969072165  C 1.74609375 12.43298969072165  2.25 12.931701030927835  2.25 13.54639175257732  L 2.25 15.302319587628862  C 2.25 15.557474226804121  2.5242187499999957 15.77319587628866  2.84765625 15.77319587628866  L 15.15234375 15.77319587628866  C 15.475781250000004 15.77319587628866  15.75 15.557474226804121  15.75 15.302319587628862  L 15.75 13.54639175257732  Z M 10.931249999999991 4.780670103092781  L 10.125 3.9845895016763033  L 10.125 12.0201030927835  C 10.125 12.634793814432985  9.62109375 13.13350515463917  9 13.13350515463917  C 8.37890625 13.13350515463917  7.875 12.634793814432985  7.875 12.0201030927835  L 7.875041749132791 3.987329815291266  L 7.071093749999996 4.78298969072165  C 6.6304687499999915 5.219072164948454  5.9203125000000085 5.219072164948454  5.479687500000004 4.78298969072165  C 5.0390625 4.346907216494848  5.0390625 3.6440721649484518  5.479687500000004 3.2079896907216487  L 8.205468750000009 0.5103092783505154  C 8.646093749999991 0.07422680412371238  9.356249999999996 0.07422680412371238  9.796875 0.5103092783505154  L 12.522656250000004 3.2079896907216487  C 12.963281250000009 3.6440721649484518  12.963281250000009 4.346907216494848  12.522656250000004 4.78298969072165  C 12.300000000000004 5.00103092783505  12.01171875 5.107731958762887  11.725781250000004 5.107731958762887  C 11.4375 5.107731958762887  11.149218749999996 4.998711340206186  10.931249999999991 4.780670103092781  Z " fill-rule="nonzero" fill="#0f8240" stroke="none" transform="matrix(1 0 0 1 186 422 )" />
+  </g>
+</svg>

+ 124 - 0
src/components/PhotoUpload/index.vue

@@ -0,0 +1,124 @@
+<template>
+    <el-upload
+        class="avatar-uploader"
+        :action="uploadImgUrl"
+        :show-file-list="false"
+        :on-success="handleAvatarSuccess"
+        :headers="headers"
+        :before-upload="beforeAvatarUpload"
+    >
+        <div class="image-box">
+            <img v-if="imageUrl" :src="imageUrl" class="img-box" />
+            <div v-else class="kong d-flex flex-cln a-c j-c">
+                <div class="d-flex a-c">
+                    <img class="mr5" src="@/assets/svg/normal_u190.svg" alt="" />
+                    <div>点击上传文件</div>
+                </div>
+            </div>
+        </div>
+    </el-upload>
+</template>
+
+<script lang="ts" setup name="PhotoUpload">
+import { ComponentInternalInstance, getCurrentInstance, ref, watch } from 'vue'
+import { ElMessage } from 'element-plus'
+import type { UploadProps } from 'element-plus'
+import { globalHeaders } from "@/utils/request";
+import { propTypes } from '@/utils/propTypes';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const props = defineProps({
+  modelValue: String,
+  // 图片数量限制
+  limit: propTypes.number.def(1),
+  // 大小限制(MB)
+  fileSize: propTypes.number.def(500),
+  // 文件类型, 例如['png', 'jpg', 'jpeg']
+  fileType: propTypes.array.def(["png", "jpg", "jpeg"])
+});
+const emit = defineEmits(['update:modelValue']);
+const baseUrl = import.meta.env.VITE_APP_BASE_API;
+const uploadImgUrl = ref(baseUrl + "/resource/oss/upload"); // 上传的图片服务器地址
+const headers = ref(globalHeaders());
+const imageUrl = ref('')
+
+watch(() => props.modelValue, async val => {
+  if (val) {
+    imageUrl.value = val as string
+  }
+}, { deep: true, immediate: true });
+
+const handleAvatarSuccess: UploadProps['onSuccess'] = (
+    response,
+    uploadFile
+) => {
+    // imageUrl.value = response.data.url
+    proxy?.$modal.closeLoading();
+    emit('update:modelValue', response.data.url)
+}
+
+const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
+    let isImg = false;
+  if (props.fileType.length) {
+    let fileExtension = "";
+    if (rawFile.name.lastIndexOf(".") > -1) {
+      fileExtension = rawFile.name.slice(rawFile.name.lastIndexOf(".") + 1);
+    }
+    isImg = props.fileType.some((type: any) => {
+      if (rawFile.type.indexOf(type) > -1) return true;
+      if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+      return false;
+    });
+  } else {
+    isImg = rawFile.type.indexOf("image") > -1;
+  }
+  if (!isImg) {
+    proxy?.$modal.msgError(
+      `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
+    );
+    return false;
+  }
+  if (props.fileSize) {
+    const isLt = rawFile.size / 1024 / 1024 < props.fileSize;
+    if (!isLt) {
+      proxy?.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
+      return false;
+    }
+  }
+  proxy?.$modal.loading("正在上传图片,请稍候...");
+}
+</script>
+
+<style lang="scss">
+.avatar-uploader {
+    width: 100%;
+
+    .el-upload {
+        width: 100%;
+    }
+}
+
+.avatar-uploader .image-box {
+    width: 100%;
+    height: 115px;
+    border-radius: 6px;
+    border: 1px dashed #0f8240;
+    background-color: rgba(0, 0, 0, 0.02);
+    box-sizing: border-box;
+}
+</style>
+<style lang="scss" scoped>
+.kong {
+    width: 100%;
+    height: 100%;
+}
+.img-box {
+    width: 100%;
+    height: 100%;
+}
+
+.def-xiao {
+    width: 103px;
+    height: 60px;
+}
+</style>

+ 75 - 0
src/utils/models.ts

@@ -0,0 +1,75 @@
+import { uploadFile } from '@/api/system/oss';
+import { VXETable, VxeColumnPropTypes } from 'vxe-table';
+
+export const cmToPx = (cm: number, dpi = 96) => {
+    return (cm * dpi) / 2.54;
+};
+export const importFileGetUrl = async (types: string[] = ['xlsx', 'xls']) => {
+    const { file } = await VXETable.readFile({
+        types
+    });
+    const curPath = URL.createObjectURL(file);
+    const formData = new FormData();
+    formData.append('file', file, file.name);
+    const { data } = await uploadFile(formData);
+    return data;
+};
+export const importFileGetUrls = async (types: string[] = ['png', 'jpg']) => {
+    const { files } = await VXETable.readFile({
+        types,
+        multiple: true
+    });
+    const promises = Array.from(files).map((file: File) => importFileGetUrlByFile(file));
+    return Promise.all(promises);
+};
+// 传入file, file.name 利用formData上传,用
+export const importFileGetUrlByFile = async (file: File) => {
+    const formData = new FormData();
+    formData.append('file', file, file.name);
+    return uploadFile(formData);
+};
+export const filterBool = (val: string) => {
+    if (val) {
+        return +val ? '是' : '否';
+    } else {
+        return '-';
+    }
+};
+export const colNoData: VxeColumnPropTypes.Formatter<any> = ({ cellValue }) => {
+    if (cellValue) {
+        return cellValue;
+    } else {
+        return '-';
+    }
+};
+
+export const formatterfilterBool: VxeColumnPropTypes.Formatter<any> = ({ cellValue }) => {
+    if (cellValue) {
+        return +cellValue ? '是' : '否';
+    } else {
+        return '-';
+    }
+};
+
+export const formatWarehouseRow = (warehouseInfo: any) => {
+    if (warehouseInfo && warehouseInfo.length) {
+        const strTem: string[] = [];
+        for (let i = 0; i < warehouseInfo.length; i++) {
+            const { warehouseName = '', shelvesName = '', warehouseSn = '', shelvesSn = '' } = warehouseInfo[i];
+            const strKf = warehouseName ? `${warehouseName}${warehouseSn ? '(' + warehouseSn + ')' : ''}` : '';
+            const strCk = shelvesName ? `${shelvesName}${shelvesSn ? '(' + shelvesSn + ')' : ''}` : '';
+            strTem.push(strKf + (strCk ? '/' + strCk : ''));
+        }
+        return strTem.toString();
+    } else {
+        return '-';
+    }
+};
+// 格式化产地
+export const formatOrigin = (adcdCodeDesc: any, nationTypeDesc: any) => {
+    if (nationTypeDesc === '中国大陆' || !nationTypeDesc) {
+        return adcdCodeDesc || '-';
+    } else {
+        return nationTypeDesc || '-';
+    }
+};

+ 1 - 1
src/utils/request.ts

@@ -301,4 +301,4 @@ export function downloadFile({ url, fileName = '', method = 'get', params = {},
     }
 }
 // 导出 axios 实例
-export default service;
+export default service;

+ 12 - 0
src/utils/ruoyi.ts

@@ -281,3 +281,15 @@ export const changeByte = (byte: number) => {
     }
     return size;
 };
+export const dataURLtoBlob = (base64Buf: string): Blob => {
+    const arr = base64Buf.split(',');
+    const typeItem = arr[0];
+    const mime = typeItem.match(/:(.*?);/)![1];
+    const bstr = window.atob(arr[1]);
+    let n = bstr.length;
+    const u8arr = new Uint8Array(n);
+    while (n--) {
+        u8arr[n] = bstr.charCodeAt(n);
+    }
+    return new Blob([u8arr], { type: mime });
+};

+ 346 - 0
src/views/auth/appuser/index.vue

@@ -0,0 +1,346 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
+      :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div class="search">
+        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="108px">
+          <el-form-item label="手机号码" prop="phone">
+            <el-input v-model="queryParams.phone" placeholder="请输入电话号码" clearable style="width: 200px"
+              @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="姓名" prop="name">
+            <el-input v-model="queryParams.name" placeholder="请输入姓名" clearable style="width: 200px"
+              @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="是否绑定邮箱" prop="emailbind">
+            <el-select v-model="queryParams.emailbind" clearable>
+              <el-option v-for="dict in common_yes_no" :value="dict.value" :label="dict.label"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="是否绑定微信" prop="wxbind">
+            <el-select v-model="queryParams.wxbind" clearable>
+              <el-option v-for="dict in common_yes_no" :value="dict.value" :label="dict.label"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header v-if="false">
+        <!-- <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport"
+              v-hasPermi="['auth:user:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row> -->
+      </template>
+
+      <el-table v-loading="loading" :data="userList" border>
+        <el-table-column type="index" width="55" align="center" label="序号" />
+        <el-table-column label="姓名" align="left" prop="name" width="250">
+          <template #default="scope">
+            <div style="display: flex;align-items: center;">
+              <el-avatar size="small" :src="scope.row.avatar" />
+              <div style="margin-left: 10px;">{{ scope.row.name }}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="手机号" align="center" prop="phone" width="150" />
+        <el-table-column label="邮箱" align="center" prop="email" width="200" />
+        <el-table-column label="绑定微信" align="center" prop="wxbind" width="90">
+          <template #default="scope">
+            <dict-tag :options="common_yes_no" :value="scope.row.wxbind"></dict-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="所在企业" align="center" prop="cpyCount" width="300">
+          <template #default="scope">
+            <div v-for="item in scope.row.cpyNames?.split(',')">{{ item }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column label="注册时间" align="center" prop="createTime" width="180" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-button size="default" type="primary" @click="handleCpyEdit(scope.row)">修改企业信息</el-button>
+            <el-button size="default" type="primary" @click="handleEdit(scope.row)">修改</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <el-dialog :close-on-click-modal="false" title="用户信息修改" v-model="userDialogVisible" width="500px" append-to-body>
+      <el-form ref="userFormRef" :model="userForm" :rules="userRules" label-width="108px">
+        <UploadAvatar title="头像" v-model="userForm.avatar"></UploadAvatar>
+
+        <el-form-item label="姓名" prop="name">
+          <el-input v-model="userForm.name" placeholder="请输入姓名" clearable />
+        </el-form-item>
+        <el-form-item label="手机号" prop="phone">
+          <el-input v-model="userForm.phone" placeholder="请输入手机号" clearable />
+        </el-form-item>
+        <el-form-item label="邮箱" prop="email">
+          <el-input v-model="userForm.email" placeholder="请输入邮箱" clearable />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitUser">确 定</el-button>
+          <el-button @click="cancelUser">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <el-dialog :close-on-click-modal="false" title="企业信息修改" v-model="cpyDialogVisible" width="500px" append-to-body>
+      <div style="display: flex;align-items: center;">
+        <el-avatar size="small" :src="currentUser?.avatar" />
+        <div style="margin-left: 10px;">【{{ currentUser?.name }}】目前已加入企业:</div>
+      </div>
+      <div class="cpy-container" v-loading="loading">
+        <div class="cpy-item" v-for="item in cpyList">
+          <span>{{ item.cpyInfo?.cpyName || '无名' }}({{ item.cpyInfo?.creditCode }})</span><el-button type="text"
+            icon="close" @click="removeUserCpy(item)"></el-button>
+        </div>
+      </div>
+      <span v-show="cpyList.length == 0">暂未加入任何企业</span>
+      <template #footer>
+        <div class="center-btn-container">
+
+          <el-button @click="handleCpyAdd" type="primary" :loading="buttonLoading">添加企业<ElIcon>
+              <Plus />
+            </ElIcon> </el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <el-drawer v-model="cpySelectVisible" size="40%" :close-on-click-modal="false" v-loading="loading">
+      <el-form :model="cpyQueryParams" ref="queryFormRef" label-width="100px" :inline="true">
+        <el-form-item label="企业名称" prop="cpyName">
+          <el-input v-model="cpyQueryParams.cpyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQueryCpy" />
+        </el-form-item>
+        <el-form-item label="社会信用代码" prop="creditCode">
+          <el-input v-model="cpyQueryParams.creditCode" placeholder="请输入社会信用代码" clearable @keyup.enter="handleQueryCpy" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQueryCpy">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQueryCpy">重置</el-button>
+        </el-form-item>
+      </el-form>
+      <el-table v-loading="loading" :data="recordCompanyList" border>
+        <el-table-column type="index" width="55" align="center" label="序号" />
+        <el-table-column label="企业名称" align="center" prop="cpyName" />
+        <el-table-column label="社会统一信用代码" align="center" prop="creditCode"></el-table-column>
+        <el-table-column label="操作" width="100">
+          <template #default="scope">
+            <el-button type="text" @click="addCPy(scope.row)">选择</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination v-show="cpyTotal > 0" :total="cpyTotal" v-model:page="cpyQueryParams.pageNum"
+        v-model:limit="cpyQueryParams.pageSize" @pagination="getCpyList" />
+    </el-drawer>
+  </div>
+</template>
+
+<script setup name="AuthUser" lang="ts">
+import { listUser, updateUser } from '@/api/auth/user';
+import { UserVO, UserQuery, UserForm } from '@/api/auth/user/types';
+import { UploadAvatar } from '@/views/components';
+import { RecordCompanyVO, RecordCompanyQuery, BindInfoCpyListVo, } from '@/api/enterprise/recordCompany/types';
+import { listRecordCompany, listByUserId, removeBindUser, adminAddUserForCpy } from '@/api/enterprise/recordCompany';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const userList = ref<UserVO[]>([]);
+const loading = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const { common_yes_no } = toRefs<any>(proxy?.useDict('common_yes_no'))
+
+
+const data = reactive<PageData<any, UserQuery>>({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: undefined,
+    phone: undefined,
+    emailbind: undefined,
+    wxbind: undefined,
+    params: {
+    }
+  },
+  rules: {
+  }
+});
+
+const { queryParams, } = toRefs(data);
+
+/** 查询app用户列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listUser(queryParams.value);
+  userList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+/**
+ * 用户修改
+ */
+const userFormRef = ref<ElFormInstance>()
+const userDialogVisible = ref(false)
+const initUserForm = (): UserForm => ({
+  id: undefined,
+  name: undefined,
+  avatar: undefined,
+  phone: undefined,
+  email: undefined,
+})
+const userForm = ref(initUserForm())
+const reset = () => {
+  userForm.value = initUserForm()
+  userFormRef.value?.resetFields()
+}
+const userRules = {
+  name: [{ required: true, trigger: 'blur', message: '姓名不能为空' }],
+  phone: [{ required: true, trigger: 'blur', message: '手机号码不能为空' }],
+}
+const buttonLoading = ref(false)
+/** 编辑用户按钮处理 */
+const handleEdit = (row: UserVO) => {
+  reset()
+  Object.assign(userForm.value, row)
+  userDialogVisible.value = true
+}
+/**取消修改用户 */
+const cancelUser = () => {
+  userDialogVisible.value = false;
+}
+/**修改用户信息 */
+const submitUser = async () => {
+  const valid = await userFormRef.value?.validate()
+  if (valid) {
+    buttonLoading.value = true
+    await updateUser(userForm.value).finally(() => buttonLoading.value = false)
+    proxy?.$modal.alert("操作成功")
+    userDialogVisible.value = false
+    getList()
+  }
+}
+const cpyDialogVisible = ref(false)
+const cpyList = ref<BindInfoCpyListVo[]>([])
+const cpySelectVisible = ref(false)
+/** 添加企业处理 */
+const handleCpyAdd = () => {
+  cpySelectVisible.value = true
+  resetQueryCpy()
+}
+/** 修改企业按钮处理 */
+const handleCpyEdit = async (row: UserVO) => {
+  currentUser.value = row
+  await loadBindCpy()
+  cpyDialogVisible.value = true
+}
+/**
+ * 查询用户的企业
+ */
+const loadBindCpy = async () => {
+  const res = await listByUserId(currentUser.value?.id as number)
+  cpyList.value = res.data
+}
+const recordCompanyList = ref<RecordCompanyVO[]>([])
+const initCpyParams = (): RecordCompanyQuery => ({
+  pageNum: 1,
+  pageSize: 10,
+  cpyName: undefined,
+  creditCode: undefined,
+  status: "1",
+
+})
+const cpyTotal = ref(0)
+const cpyQueryParams = ref(initCpyParams())
+/**
+ * 查询所有企业
+ */
+const getCpyList = async () => {
+  loading.value = true;
+  const res = await listRecordCompany(cpyQueryParams.value);
+  recordCompanyList.value = res.rows;
+  cpyTotal.value = res.total;
+  loading.value = false;
+}
+/** 搜索按钮操作 */
+const handleQueryCpy = () => {
+  cpyQueryParams.value.pageNum = 1;
+  getCpyList();
+}
+const currentUser = ref<UserVO | undefined>(undefined)
+const cpyQueryParamsRef = ref<ElFormInstance>()
+/** 重置按钮操作 */
+const resetQueryCpy = () => {
+  cpyQueryParamsRef.value?.resetFields();
+  cpyQueryParams.value = initCpyParams()
+  handleQueryCpy();
+}
+const addCPy = async (row: RecordCompanyVO) => {
+  await proxy?.$modal.confirm(`是否确定将【${currentUser.value?.name}】添加到【${row.cpyName}】?`)
+  loading.value = true
+  await adminAddUserForCpy({ cpyid: row.id as number, userid: currentUser.value?.id as number }).finally(() => loading.value = false)
+  proxy?.$modal.alert("操作成功")
+  await loadBindCpy()
+  cpySelectVisible.value = false
+}
+//移除企业
+const removeUserCpy = async (row: BindInfoCpyListVo) => {
+  await proxy?.$modal.confirm(`是否确定将用户踢出【${row.cpyInfo?.cpyName}】?`)
+  loading.value = true
+  buttonLoading.value = true
+  await removeBindUser({ cpyid: row.cpyInfo?.id as number, userids: [row.cpyInfo?.userid as number] }).catch((e) => {
+    loading.value = false;
+    throw e
+  }).finally(() => { buttonLoading.value = false })
+  await loadBindCpy()
+  await getList()
+  loading.value = false;
+}
+onMounted(() => {
+  getList();
+});
+</script>
+<style scoped lang="scss">
+.cpy-container {
+  margin-top: 20px;
+  margin-bottom: 20px;
+
+  .cpy-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+    border-bottom: 1px solid green;
+  }
+}
+
+.center-btn-container {
+  display: flex;
+
+  .el-button {
+    flex: 1;
+  }
+}
+</style>

+ 209 - 0
src/views/auth/appuser/userbind.vue

@@ -0,0 +1,209 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div class="search">
+                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="108px">
+                    <el-form-item label="关键字" prop="keywords">
+                        <el-input v-model="queryParams.keywords" placeholder="请输入关键字" clearable style="width: 200px" @keyup.enter="handleQuery" />
+                    </el-form-item>
+                    <el-form-item label="状态" prop="status">
+                        <el-select v-model="queryParams.status" clearable>
+                            <el-option v-for="dict in approval_query_type" :value="dict.value" :label="dict.label"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item>
+                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </transition>
+
+        <el-card shadow="never">
+            <template #header v-if="false"></template>
+
+            <el-table v-loading="loading" :data="userList" border>
+                <el-table-column type="index" width="55" align="center" label="序号" />
+                <el-table-column label="姓名" align="left" prop="name" width="200">
+                    <template #default="scope">
+                        <div style="display: flex;align-items: center;">
+                            <el-avatar size="small" :src="scope.row.userInfo.avatar" />
+                            <div style="margin-left: 10px;">{{ scope.row.userInfo.name }}</div>
+                        </div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="手机号" align="left" prop="phone" width="200">
+                    <template #default="scope">
+                        <div style="display: flex;align-items: center;">
+                            <div style="margin-left: 10px;">{{ scope.row.userInfo.phone }}</div>
+                        </div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="申请企业" align="center" prop="cpyName" width="300">
+                    <template #default="scope">
+                        <div style="display: flex;align-items: center;">
+                            <el-avatar size="small" :src="scope.row.cpyInfo.storePhoto" />
+                            <div style="margin-left: 10px;">{{ scope.row.cpyInfo.cpyName }}</div>
+                        </div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="统一社会信用代码" align="center" prop="cpyName" width="250">
+                    <template #default="scope">
+                        <div style="margin-left: 10px;">{{ scope.row.cpyInfo.creditCode }}</div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="时间申请" align="center" prop="createTime" width="200" />
+                <el-table-column prop="res" width="90" label="状态">
+                    <template #default="{ row }">
+                        <div :style="{ color: approval_query_type.find((item: any) => item.value === row.res).elTagClass }">
+                            {{ selectDictLabel(approval_query_type, row.res) }}
+                        </div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                    <template #default="scope">
+                        <div v-if="scope.row.res == '0'">
+                            <el-button @click="handleApproval(scope.row, '1')" type="success">审核通过</el-button>
+                            <el-button @click="handleApproval(scope.row, '2')" type="warning">审核不通过</el-button>
+                        </div>
+                    </template>
+                </el-table-column>
+            </el-table>
+            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+    </div>
+</template>
+
+<script setup name="Userbind" lang="ts">
+import { bindInfoApproval } from '@/api/settled';
+import { BindInfoCpyListVo, QueryUserBindInfoBo } from '@/api/enterprise/recordCompany/types';
+import { listUserBindInfo } from '@/api/enterprise/recordCompany';
+import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const userList = ref<BindInfoCpyListVo[]>([]);
+const loading = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const { approval_query_type } = toRefs<any>(proxy?.useDict('approval_query_type'));
+
+const data = reactive<PageData<any, QueryUserBindInfoBo>>({
+    form: {},
+    queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        cpyName: undefined,
+        userName: undefined,
+        keywords: undefined,
+        status: '0',
+        params: {}
+    },
+    rules: {}
+});
+
+const { queryParams } = toRefs(data);
+
+/** 查询app用户列表 */
+const getList = async () => {
+    loading.value = true;
+    const res = await listUserBindInfo(queryParams.value);
+    userList.value = res.rows;
+    total.value = res.total;
+    loading.value = false;
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+    queryParams.value.pageNum = 1;
+    getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+    queryFormRef.value?.resetFields();
+    handleQuery();
+};
+
+/**
+ * 申请审批
+ */
+const handleApproval = async (row: any, res: string) => {
+    if (res === '1') {
+        ElMessageBox.confirm('该成员审核通过?', '提示', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            type: 'success',
+            icon: markRaw(CircleCheck)
+        })
+            .then(() => {
+                const params = {
+                    approvalType: '2',
+                    targetId: row.id,
+                    res
+                };
+                approvalAjax(params);
+            })
+            .catch(() => {
+                proxy?.$modal.msgWarning('取消审核');
+            });
+    } else {
+        ElMessageBox.prompt('该成员审核不通过', '提示', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            inputPlaceholder: '不通过理由',
+            inputErrorMessage: '请填写不通过理由',
+            type: 'error',
+            icon: markRaw(CircleClose),
+            inputValidator: (value) => {
+                return value ? true : false;
+            }
+        })
+            .then(({ value }) => {
+                const params = {
+                    approvalType: '2',
+                    targetId: row.id,
+                    res,
+                    msg: value
+                };
+                approvalAjax(params);
+            })
+            .catch(() => {
+                proxy?.$modal.msgWarning('取消审核');
+            });
+    }
+};
+const approvalAjax = async (params: any) => {
+    proxy?.$modal.loading('审核中...');
+    const res = await bindInfoApproval(params).catch(() => {});
+    proxy?.$modal.closeLoading();
+    if (!res) return;
+    proxy?.$modal.msgSuccess('操作完成');
+    getList();
+};
+
+onMounted(() => {
+    getList();
+});
+</script>
+<style scoped lang="scss">
+.cpy-container {
+    margin-top: 20px;
+    margin-bottom: 20px;
+
+    .cpy-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: baseline;
+        border-bottom: 1px solid green;
+    }
+}
+
+.center-btn-container {
+    display: flex;
+
+    .el-button {
+        flex: 1;
+    }
+}
+</style>

+ 108 - 0
src/views/components/AreaCascader.vue

@@ -0,0 +1,108 @@
+<!--
+ * @Description: 
+ * @Version: 
+ * @Author: 黄先伟
+ * @Date: 2024-02-06 09:05:33
+-->
+
+<template>
+    <el-cascader ref="cascadeRef" class="base-input" v-model="value" :props="propsJson" @change="change" clearable style="width: 100%;" />
+</template>
+
+<script setup name="AreaCascader" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+import type { CascaderProps } from 'element-plus';
+import { listChildrenByCode, getAdcdByCode } from '@/api/adcd';
+// import { citys } from '@/utils/citys';
+const citys = [{ label: '云南省', value: '530000' }];
+
+const emit = defineEmits(['update:modelValue', 'change']);
+const cascadeRef = ref();
+const props = defineProps({
+    modelValue: [String, Array],
+    zlevel: propTypes.number.def(3),
+    multiple: propTypes.bool.def(false)
+});
+const value = ref();
+const propsJson: CascaderProps = {
+    lazy: true,
+    multiple: props.multiple,
+    lazyLoad(node, resolve) {
+        console.log(node);
+        const { level, value } = node;
+        let nodes = [];
+        if (!level) {
+            nodes = citys.map(({ label, value }) => ({ label, value }));
+            resolve(nodes);
+        } else {
+            listChildrenByCode({ adcdCode: value, leval: (level as number) + 1, pageSize: 1000 }).then((res) => {
+                const rows = res.rows;
+                nodes = rows.map(({ adcdName, adcdCode }: any) => ({ label: adcdName, value: adcdCode, leaf: level >= props.zlevel }));
+                resolve(nodes);
+            });
+        }
+    }
+};
+watch(
+    () => props.modelValue,
+    (val) => {
+        if (val) {
+            if (!props.multiple) {
+                const c8 = val.slice(0, 9);
+                const c6 = val.slice(0, 6);
+                const c4 = val.slice(0, 4);
+                const c2 = val.slice(0, 2);
+                if (props.zlevel === 3) {
+                    value.value = [c2 + '0000', c4 + '00000000', c6 + '000000', val];
+                }
+                if (props.zlevel === 4) {
+                    value.value = [c2 + '0000', c4 + '00000000', c6 + '000000', c8 + '000', val];
+                }
+                if (props.zlevel === 2) {
+                    value.value = [c2 + '0000', c4 + '00000000', c6 + '000000'];
+                    console.log(value.value);
+                }
+            } else {
+                if (Array.isArray(val)) {
+                    const vl: any = [];
+                    val.forEach((e: any) => {
+                        vl.push([e.slice(0, 2) + '0000', e.slice(0, 4) + '00000000', e.slice(0, 6) + '000000', e]);
+                    });
+                    value.value = vl;
+                }
+            }
+        } else {
+            value.value = []
+        }
+    },
+    { immediate: true }
+);
+const change = (event: any) => {
+    const checkedNodes = cascadeRef.value.getCheckedNodes();
+    if (props.multiple) {
+        if (event && event.length) {
+            const vl: any = [];
+            const address: any = [];
+            event.forEach((e: any) => {
+                vl.push(e[e.length - 1]);
+            });
+            checkedNodes.forEach((e: any) => {
+                address.push(e.pathLabels.join(''))
+            });
+            emit('update:modelValue', vl);
+            console.log(address.toString());
+            emit('change', { value, vl, name: address.toString() });
+        } else {
+            emit('update:modelValue', null);
+        }
+    } else {
+        if (event && event.length) {
+            const labels = checkedNodes[0].pathLabels
+            emit('update:modelValue', event[event.length - 1]);
+            emit('change', { value: event[event.length - 1], name: labels.join(''),  labels});
+        } else {
+            emit('update:modelValue', null);
+        }
+    }
+};
+</script>

+ 47 - 0
src/views/components/AreaView.vue

@@ -0,0 +1,47 @@
+<!--
+ * @Description: 
+ * @Version: 
+ * @Author: 黄先伟
+ * @Date: 2024-02-06 16:09:19
+-->
+<template>
+    <span>{{adcdName}}</span>
+</template>
+
+<script setup name="AreaView" lang="ts">
+import { getAdcdByCode } from '@/api/adcd';
+import { propTypes } from '@/utils/propTypes';
+const adcdName = ref('');
+const props = defineProps({
+  value: String,
+  multiple: propTypes.bool.def(false)
+});
+const getByCodeFn = async (code: string) => {
+  const res = await getAdcdByCode(code);
+  if (!res || res.code !== 200) return;
+  adcdName.value = res.data?.fullName || '';
+};
+const getByCodeFnArr = async (vl: any) => {
+  const address = []
+  for (let i = 0; i < vl.length; i++) {
+    const element = vl[i];
+    const res = await getAdcdByCode(element);
+    address.push(res.data.fullName)
+  }
+  adcdName.value = address.toString()
+}
+watch(
+  () => props.value,
+  (val) => {
+    if (val) {
+      if (!props.multiple) {
+        getByCodeFn(val);
+      } else {
+        getByCodeFnArr(val)
+      }
+    }
+  },
+  { immediate: true }
+);
+</script>
+<style lang="scss" scoped></style>

+ 15 - 0
src/views/components/Breadcrumb.vue

@@ -0,0 +1,15 @@
+<template>
+    <div class="breadcrumb-box border-bottom">
+        <slot></slot>
+    </div>
+</template>
+<script setup name="Breadcrumb" lang="ts"></script>
+<style lang="scss" scoped>
+.breadcrumb-box {
+  padding: 16px;
+  font-size: 16px;
+  line-height: 1.2;
+  color: #666;
+  background-color: #fff;
+}
+</style>

+ 37 - 0
src/views/components/DateRange.vue

@@ -0,0 +1,37 @@
+<template>
+    <el-date-picker
+        v-model="dateTime"
+        clearable
+        type="daterange"
+        class="flex1"
+        value-format="YYYY-MM-DD"
+        range-separator="至"
+        start-placeholder="开始时间"
+        end-placeholder="结束时间"
+        @change="changeDate"
+    />
+</template>
+
+<script setup name="DateRange" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+const emit = defineEmits(['update:startDate', 'update:endDate', 'update:modelValue', 'change']);
+const dateTime = ref<string[]>([])
+const props = defineProps({
+   modelValue: propTypes.any.def([]),
+   startDate: propTypes.string.def(''),
+   endDate: propTypes.string.def(''),
+});
+const changeDate = (val: string[]) => {
+    emit('update:modelValue', val)
+    emit('update:startDate', val?.[0])
+    emit('update:endDate', val?.[1])
+    emit('change', val)
+}
+watch(() => props.modelValue, (val) => {
+    dateTime.value = val
+    if (!val?.length) {
+        emit('update:startDate', '')
+        emit('update:endDate', '')
+    }
+})
+</script>

+ 16 - 0
src/views/components/DescInfo.vue

@@ -0,0 +1,16 @@
+<template>
+    <div>
+        <el-row :gutter="gutter">
+            <slot></slot>
+        </el-row>
+    </div>
+</template>
+
+<script setup name="DescInfo" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
+const props = defineProps({
+    span: propTypes.number.def(8),
+    gutter: propTypes.number.def(10)
+});
+</script>

+ 36 - 0
src/views/components/DescItem.vue

@@ -0,0 +1,36 @@
+<template>
+    <el-col :span="span">
+        <div class="desc-item d-flex">
+            <div :style="{ fontSize: size + 'px' }" class="desc-label">{{ label }}</div>
+            <div :style="{ fontSize: size + 'px' }" class="desc-value flex1" :class="{ 'text-overflow1': isSv }">
+                <slot></slot>
+            </div>
+        </div>
+    </el-col>
+</template>
+
+<script setup name="DescItem" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
+const props = defineProps({
+    span: propTypes.number.def(6),
+    label: String,
+    isSv: Boolean,
+    size: propTypes.number.def(16)
+});
+</script>
+<style lang="scss" scoped>
+.desc-item {
+    padding: 4px 0;
+    font-size: 16px;
+    line-height: 1.6;
+}
+.desc-label {
+    font-size: 16px;
+    color: rgba(51, 51, 51, 1);
+}
+.desc-value {
+    font-size: 16px;
+    color: rgba(102, 102, 102, 1);
+}
+</style>

+ 38 - 0
src/views/components/DescItemTop.vue

@@ -0,0 +1,38 @@
+<template>
+    <div class="desc-item">
+        <div class="desc-label" :style="{ fontSize: size + 'px' }">{{ label }}</div>
+        <div class="desc-value" :style="{ fontSize: size + 'px' }" :class="{ 'text-overflow1': isSv }">
+            <slot></slot>
+        </div>
+    </div>
+</template>
+
+<script setup name="DescItemTop" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
+const props = defineProps({
+    span: propTypes.number.def(6),
+    label: String,
+    isSv: Boolean,
+    size: propTypes.number.def(16)
+});
+</script>
+<style lang="scss" scoped>
+.desc-item {
+    padding: 4px 0;
+    font-size: 16px;
+    line-height: 1.6;
+}
+
+.desc-label {
+    padding-bottom: 10px;
+    font-size: 16px;
+    color: rgba(51, 51, 51, 1);
+}
+
+.desc-value {
+    font-size: 16px;
+    color: rgba(102, 102, 102, 1);
+    white-space: pre-line;
+}
+</style>

+ 63 - 0
src/views/components/FileLook.vue

@@ -0,0 +1,63 @@
+<template>
+    <transition-group class="upload-file-list" name="el-fade-in-linear" tag="div">
+        <el-row :gutter="60">
+            <el-col :span="span" v-for="(file, index) in fileList" :key="index">
+                <div class="upload-list-img d-flex a-c" @click="show2 = true;lookIndex=index">
+                    <img src="@/assets/images/icon_pic.png" alt="" />
+                    <el-tooltip class="box-item" effect="dark" :content="file.fileName" placement="top">
+                        <div class="item-text flex1 sv-1" style="color: #3e7b65;">
+                            {{ file.fileName }}
+                        </div>
+                    </el-tooltip>
+                </div>
+            </el-col>
+        </el-row>
+        <div v-if="!fileList.length">-</div>
+    </transition-group>
+    <ImageViewer v-model:show="show2" :imgs="fileList.map((item: any) => item.url)" :index="lookIndex"></ImageViewer>
+</template>
+
+<script setup lang="ts">
+import { download } from '@/utils/request';
+import { propTypes } from '@/utils/propTypes';
+import { changeByte } from '@/utils/ruoyi';
+import { ImageViewer } from '@/views/components';
+const props = defineProps({
+    modelValue: [String, Object, Array],
+    span: propTypes.number.def(8),
+    isObject: propTypes.bool.def(true),
+    isFile: propTypes.bool.def(true)
+});
+const show2 = ref(false);
+const lookIndex = ref(0);
+const fileList = ref<any>([]);
+watch(
+    () => props.modelValue,
+    async (val) => {
+        if (val) {
+            let list = [];
+            if (Array.isArray(val)) {
+                list = val;
+            } else if (props.isObject) {
+                list = [val];
+            }
+            fileList.value = [...list];
+        } else {
+            fileList.value = [];
+            return [];
+        }
+    },
+    { deep: true, immediate: true }
+);
+</script>
+
+<style scoped lang="scss">
+.upload-list-img {
+    cursor: pointer;
+    margin-top: 10px;
+
+    &:first-child {
+        margin-top: 0;
+    }
+}
+</style>

+ 51 - 0
src/views/components/H5ModelLook.vue

@@ -0,0 +1,51 @@
+<template>
+    <vxe-modal
+        v-model="dialogVisible"
+        :title="title"
+        resize
+        :show-footer="false"
+        destroy-on-close
+        transfer
+        height="80vh"
+        mask-closable
+        @hide="close"
+        :width="width"
+    >
+        <template #default>
+            <iframe :src="src" class="iframe-wrapper"></iframe>
+        </template>
+    </vxe-modal>
+</template>
+
+<script setup name="addSpec" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
+const emit = defineEmits(['update:show', 'close', 'success']);
+
+const dialogVisible = ref(false);
+const props = defineProps({
+    show: propTypes.bool.def(false),
+    title: propTypes.string.def('查看追溯信息'),
+    width: propTypes.string.def('366px'),
+    src: propTypes.string.def('')
+});
+const close = () => {
+    emit('update:show', false);
+    emit('close', true);
+};
+watch(
+    () => props.show,
+    (val) => {
+        console.log(val);
+        dialogVisible.value = val;
+    },
+    { immediate: true }
+);
+</script>
+<style lang="scss" scoped>
+.iframe-wrapper {
+    width: 100%;
+    height: calc(100% - 1.6em);
+    border: none;
+}
+</style>

+ 24 - 0
src/views/components/ImageViewer.vue

@@ -0,0 +1,24 @@
+<template>
+    <el-image-viewer v-if="show" :url-list="(imgs as string[])" :initialIndex="index" @close="close" @cover-click="close"></el-image-viewer>
+</template>
+
+<script setup name="CardItem" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+
+const emit = defineEmits(['update:show']);
+const props = defineProps({
+    show: Boolean,
+    imgs: Array,
+    index: propTypes.number.def(0)
+});
+const close = () => {
+    emit('update:show', false)
+}
+onMounted(() => {
+    document.addEventListener('click',function(e: any){
+        if(e.target.className=="el-image-viewer__mask"){
+            close()
+        }
+    });
+})
+</script>

+ 314 - 0
src/views/components/MapContainer.vue

@@ -0,0 +1,314 @@
+<!--
+ * @Description: 
+ * @Version: 
+ * @Author: 黄先伟
+ * @Date: 2024-01-10 17:04:41
+-->
+<template>
+    <div class="d-flex j-sb" style="padding: 10px 0 20px;">
+        <el-space :size="20">
+            <el-button @click="addLayers()" color="#02a7f0">添加卫星图层</el-button>
+            <el-button @click="removeLayers()" type="warning">移除卫星图层</el-button>
+            <template v-if="query.mode !== '1'">
+                <el-button type="primary" @click="createPolygon">新建地块</el-button>
+                <el-button @click="endPolygon" type="info" plain>取消选中</el-button>
+                <el-button @click="removePolygon" type="danger" plain>删除选中地块</el-button>
+                <el-button @click="clearPolygon" type="danger" plain>删除所有地块</el-button>
+            </template>
+        </el-space>
+        <el-select
+            filterable
+            remote
+            v-model="keywords"
+            reserve-keyword
+            placeholder="请输入关键字定位到你的园区"
+            :remote-method="remoteMethod"
+            @change="searchKeywords"
+            :loading="loading"
+            style="width: 240px"
+        >
+            <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+    </div>
+    <div :id="el" ref="mapViewRef" class="map-container"></div>
+    <btm-wrap v-if="query.mode !== '1'">
+        <el-space :size="24">
+            <el-button @click="$router.go(-1)">取消</el-button>
+            <el-button @click="save" type="primary">保存</el-button>
+        </el-space>
+    </btm-wrap>
+</template>
+<script name="MapContainer" setup lang="ts">
+
+import { onMounted, onUnmounted, getCurrentInstance } from 'vue';
+import html2canvas from 'html2canvas';
+import AMapLoader from '@amap/amap-jsapi-loader';
+import cache from '@/plugins/cache';
+import { dataURLtoBlob } from '@/utils/ruoyi';
+import { uploadFile } from '@/api/system/oss';
+import { useRoute, onBeforeRouteLeave } from 'vue-router';
+import router from '@/router';
+
+const route = useRoute();
+const { query } = route;
+const { proxy, appContext } = getCurrentInstance() as ComponentInternalInstance;
+const { Bus } = appContext.config.globalProperties;
+const loading = ref(false);
+const options = ref<any[]>([]);
+const flag = ref(false)
+const props = defineProps({
+    el: {
+        type: String,
+        default: 'container'
+    },
+    pathsList: {
+        type: Array<any>,
+        default: []
+    }
+});
+let mapData = reactive<any>({
+    map: null,
+    polyEditor: null,
+    AMap: null,
+    Satellite: null
+});
+const keywords = ref('');
+const searchKeywords = (event: string) => {
+    const item = options.value.find(({ id }) => id === event);
+    const { location, name } = item;
+    if (location) {
+        console.log(location);
+        mapData.map.setCenter(location);
+    } else if (name) {
+        mapData.map.setCity(name);
+    }
+};
+const remoteMethod = (keywords: string) => {
+    if (!keywords) {
+        return;
+    }
+    loading.value = true;
+    let autoComplete = new mapData.AMap.Autocomplete();
+    autoComplete.search(keywords, function (status: string, result: any) {
+        const tips = result.tips.filter((item: any) => item.id);
+        options.value = [...tips];
+        loading.value = false;
+    });
+};
+const paths = ref<any>({});
+const initMap = (positions: any[] = []) => {
+    AMapLoader.load({
+        key: '26b919a68880ad60637f5cabd6c94a76', // 申请好的Web端开发者Key,首次调用 load 时必填
+        version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
+        plugins: [
+            'AMap.PolygonEditor',
+            'AMap.GeometryUtil',
+            'AMap.ToolBar',
+            'AMap.ControlBar',
+            'AMap.MouseTool',
+            'AMap.PlaceSearch',
+            'AMap.AutoComplete'
+        ] // 需要使用的的插件列表,如比例尺'AMap.Scale'等
+    })
+        .then((AMap) => {
+            mapData.AMap = AMap;
+            mapData.Satellite = new mapData.AMap.TileLayer.Satellite({
+                zooms: [1, 24],
+                zIndex: 8,
+                heightFactor: 2 // 2
+            });
+            mapData.map = new AMap.Map(props.el, {
+                // 设置地图容器id
+                viewMode: '3D', // 是否为3D地图模式
+                zoom: 14.8, // 初始化地图级别
+                resizeEnable: true,
+                center: [102.705207, 25.049848],
+                WebGLParams: {
+                    preserveDrawingBuffer: true
+                }
+            });
+            mapData.map.addLayer(mapData.Satellite);
+            const toolbar = new AMap.ToolBar(); //缩放工具条实例化
+            mapData.map.addControl(toolbar);
+            const ControlBar = new AMap.ControlBar(); //缩放工具条实例化
+            mapData.map.addControl(ControlBar);
+            // 获取传入的path
+            const curPaths = positions.map((path) =>
+                path.filter(({ lat, lng }: any, index: number) => !(lat === path[0].lat && path[0].lng === lng) || !index)
+            );
+            const addPolygon = curPaths.map((path) => new AMap.Polygon({ path: path.map(({ lat, lng }: any) => new AMap.LngLat(lng, lat)) }));
+            mapData.map.add(addPolygon);
+            mapData.map.setFitView(addPolygon, false, [60, 60, 60, 60], 16);
+            if (query.mode !== '1') {
+                mapData.polyEditor = new AMap.PolygonEditor(mapData.map);
+                mapData.polyEditor.addAdsorbPolygons(addPolygon);
+                for (let index = 0; index < addPolygon.length; index++) {
+                    const polygon = addPolygon[index];
+                    setPaths(polygon);
+                    polygon.on('dblclick', () => {
+                        mapData.polyEditor.setTarget(polygon);
+                        mapData.polyEditor.open();
+                    });
+                }
+                mapData.polyEditor.on('add', function (data: any) {
+                    let polygon = data.target;
+                    mapData.polyEditor.addAdsorbPolygons(polygon);
+                    setPaths(polygon);
+                    polygon.on('dblclick', () => {
+                        mapData.polyEditor.setTarget(polygon);
+                        mapData.polyEditor.open();
+                    });
+                });
+            }
+        })
+        .catch((e) => {
+            console.log(e);
+        });
+};
+const addLayers = () => {
+    mapData.map.addLayer(mapData.Satellite);
+};
+const removeLayers = () => {
+    mapData.map.removeLayer(mapData.Satellite);
+};
+const createPolygon = () => {
+    mapData.polyEditor.close();
+    mapData.polyEditor.setTarget();
+    mapData.polyEditor.open();
+};
+
+const setPaths = (polygon: any) => {
+    const path = polygon.getPath();
+    const _amap_id = polygon._amap_id;
+    const areaNum = ringArea(path);
+    paths.value[_amap_id] = { path, areaNum };
+    return paths.value;
+};
+const endPolygon = () => {
+    mapData.polyEditor.close();
+    const polygon = mapData.polyEditor.getTarget();
+    if (polygon) {
+        setPaths(polygon);
+    }
+};
+
+const save = () => {
+    if (flag.value) {
+        return
+    }
+    proxy?.$modal.loading('保存中');
+    flag.value = true
+    mapData.polyEditor.close();
+    const polygon = mapData.polyEditor.getTarget();
+    if (polygon) {
+        setPaths(polygon);
+    }
+    const bounds = mapData.map.setFitView();
+    if (bounds) {
+        setTimeout(() => {
+            getImageCover();
+        }, 1000)
+    }
+};
+const removeIds = ref<any[]>([]);
+const removePolygon = () => {
+    mapData.polyEditor.close();
+    const polygon = mapData.polyEditor.getTarget();
+    const _amap_id = polygon._amap_id;
+    delete paths.value[_amap_id];
+    removeIds.value.push(_amap_id);
+    mapData.polyEditor.removeAdsorbPolygons([polygon]);
+    mapData.map.remove(polygon);
+};
+const clearPolygon = () => {
+    paths.value = {};
+    if (mapData.polyEditor) {
+        mapData.polyEditor.close();
+        mapData.polyEditor.clearAdsorbPolygons();
+        if (mapData.map.getAllOverlays('polygon')) {
+            const mapPolyArr = mapData.map.getAllOverlays('polygon');
+            let arr: any[] = [];
+            mapPolyArr.forEach((polygon: any) => {
+                arr.push(polygon);
+            });
+            mapData.map.remove(arr);
+        }
+    }
+};
+const ringArea = (path: any) => {
+    const squareMeters: number = mapData.AMap.GeometryUtil.ringArea(path);
+    return squareMeterToAcre(squareMeters);
+};
+const squareMeterToAcre = (squareMeters: number) => {
+    return squareMeters / (60 * 175); // 将平方米转换为亩数
+};
+const mapViewRef = ref<HTMLElement>();
+const getImageCover = async () => {
+    const canvas = await html2canvas(mapViewRef.value as HTMLElement, {
+        scale: 1,
+        logging: false,
+        useCORS: false
+    });
+    let type = 'png';
+    let imgData = canvas.toDataURL(type);
+    // 照片格式处理
+    let _fixType = function (type: string) {
+        type = type.toLowerCase().replace(/jpg/i, 'jpeg');
+        let r: any = type.match(/png|jpeg|bmp|gif/);
+        return 'image/' + r ? r[0] : '';
+    };
+    imgData = imgData.replace(_fixType(type), 'image/octet-stream');
+    const blobFile: Blob = dataURLtoBlob(imgData);
+    getImgUrl(blobFile);
+};
+const getImgUrl = async (blobFile: Blob) => {
+    const formdata = new FormData();
+    let fileBlob = new File([blobFile], new Date().getTime() + '.png');
+    formdata.append('file', fileBlob);
+    const res = await uploadFile(formdata);
+    if (!res || res.code !== 200) return;
+    const postionImg = res.data.url;
+    const pos: any[] = [];
+    let area = 0;
+    Object.entries(paths.value).forEach(([key, value]: any) => {
+        if (!removeIds.value.includes(+key)) {
+            const arrPath = value.path.map(({ lat, lng }: any) => ({ lat, lng }));
+            pos.push([...arrPath, arrPath[0]]);
+            area += value.areaNum;
+        }
+    });
+    area = Math.round(area * 100) / 100;
+    cache.session.setJSON('changeArea', { postionImg: pos && pos.length ? postionImg : '', positions: [...pos], area });
+    clearPolygon();
+    proxy?.$modal.closeLoading()
+    flag.value = false
+    router.go(-1);
+};
+
+onMounted(() => {
+    const positions = ref<any[]>([]);
+    positions.value = cache.session.getJSON('positions');
+    initMap(positions.value);
+    cache.session.remove('positions');
+});
+onUnmounted(() => {
+    mapData.map?.destroy();
+});
+
+onBeforeRouteLeave((to, from, next) => {
+    cache.session.remove('positions');
+    try {
+        console.log('hehe');
+        clearPolygon();
+        next();
+    } catch {
+        next();
+    }
+});
+</script>
+<style scoped>
+.map-container {
+    width: 100%;
+    height: 100%;
+}
+</style>

+ 239 - 0
src/views/components/UploadAvatar.vue

@@ -0,0 +1,239 @@
+<template>
+    <div class="head-img p-rtv c-s-p" @click="editCropper()">
+        <slot>
+            <div class="d-flex a-c p-rtv head-img-box" :style="{ width: size + 'px', height: size + 'px' }">
+                <HAvatar :size="size" :src="(options.img as string)" :name="options.name" :defSrc="defSrc" :fit="fit" :shape="shape"></HAvatar>
+                <div v-if="isIcon" class="icon-edit">
+                    <el-icon><EditPen /></el-icon>
+                </div>
+            </div>
+        </slot>
+        <el-dialog :title="title" v-model="open" width="800px" custom-class="custom-dialog" append-to-body @opened="modalOpened" @close="closeDialog">
+            <el-row>
+                <el-col :xs="24" :md="12" :style="{ height: '350px' }">
+                    <vue-cropper
+                        ref="cropper"
+                        :img="options.img"
+                        :info="true"
+                        :autoCrop="options.autoCrop"
+                        :autoCropWidth="options.autoCropWidth"
+                        :autoCropHeight="options.autoCropHeight"
+                        :fixedBox="options.fixedBox"
+                        :outputType="options.outputType"
+                        @realTime="realTime"
+                        v-if="visible"
+                    />
+                </el-col>
+                <el-col :xs="24" :md="12" :style="{ height: '350px' }">
+                    <div class="avatar-upload-preview">
+                        <img :src="options.previews.url" :style="options.previews.img" />
+                    </div>
+                </el-col>
+            </el-row>
+            <br />
+            <el-row>
+                <el-col :lg="2" :md="2">
+                    <el-upload
+                        action="#"
+                        :http-request="requestUpload"
+                        :show-file-list="false"
+                        accept=".png,.jpg,.jpeg,.bmp"
+                        :before-upload="beforeUpload"
+                    >
+                        <el-button>
+                            选择
+                            <el-icon class="el-icon--right">
+                                <Upload />
+                            </el-icon>
+                        </el-button>
+                    </el-upload>
+                </el-col>
+                <el-col :lg="{ span: 1, offset: 2 }" :md="2">
+                    <el-button icon="Plus" @click="changeScale(1)"></el-button>
+                </el-col>
+                <el-col :lg="{ span: 1, offset: 1 }" :md="2">
+                    <el-button icon="Minus" @click="changeScale(-1)"></el-button>
+                </el-col>
+                <el-col :lg="{ span: 1, offset: 1 }" :md="2">
+                    <el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
+                </el-col>
+                <el-col :lg="{ span: 1, offset: 1 }" :md="2">
+                    <el-button icon="RefreshRight" @click="rotateRight()"></el-button>
+                </el-col>
+                <el-col :lg="{ span: 2, offset: 6 }" :md="2">
+                    <el-button type="primary" @click="uploadImg()">提 交</el-button>
+                </el-col>
+            </el-row>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup lang="ts">
+import 'vue-cropper/dist/index.css';
+import { VueCropper } from 'vue-cropper';
+import { uploadAvatar } from '@/api/system/user';
+import useUserStore from '@/store/modules/user';
+import { uploadFile } from '@/api/system/oss';
+import { propTypes } from '@/utils/propTypes';
+
+interface Options {
+    img: string | ArrayBuffer | null; // 裁剪图片的地址
+    autoCrop: boolean; // 是否默认生成截图框
+    name: string; // 是否默认生成截图框
+    autoCropWidth: number; // 默认生成截图框宽度
+    autoCropHeight: number; // 默认生成截图框高度
+    fixedBox: boolean; // 固定截图框大小 不允许改变
+    fileName: string;
+    previews: any; // 预览数据
+    outputType: string;
+    visible: boolean;
+}
+const props = defineProps({
+    title: propTypes.string.def('修改头像'),
+    modelValue: propTypes.string.def(''),
+    name: propTypes.string.def(''),
+    defSrc: propTypes.string.def(''),
+    isIcon: propTypes.bool.def(true),
+    fit: propTypes.any.def('cover'),
+    shape: propTypes.any.def('circle'),
+    size: propTypes.number.def(82),
+});
+
+const userStore = useUserStore();
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const open = ref(false);
+const visible = ref(false);
+const cropper = ref<any>({});
+//图片裁剪数据
+const options = reactive<Options>({
+    img: '',
+    name: '',
+    autoCrop: true,
+    autoCropWidth: 200,
+    autoCropHeight: 200,
+    fixedBox: true,
+    outputType: 'png',
+    fileName: '',
+    previews: {},
+    visible: false
+});
+
+/** 编辑头像 */
+const editCropper = () => {
+    open.value = true;
+};
+/** 打开弹出层结束时的回调 */
+const modalOpened = () => {
+    visible.value = true;
+};
+/** 覆盖默认上传行为 */
+const requestUpload = (): any => {};
+/** 向左旋转 */
+const rotateLeft = () => {
+    cropper.value.rotateLeft();
+};
+/** 向右旋转 */
+const rotateRight = () => {
+    cropper.value.rotateRight();
+};
+/** 图片缩放 */
+const changeScale = (num: number) => {
+    num = num || 1;
+    cropper.value.changeScale(num);
+};
+/** 上传预处理 */
+const beforeUpload = (file: any) => {
+    if (file.type.indexOf('image/') == -1) {
+        proxy?.$modal.msgError('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。');
+    } else {
+        const reader = new FileReader();
+        reader.readAsDataURL(file);
+        reader.onload = () => {
+            options.img = reader.result;
+            options.fileName = file.name;
+        };
+    }
+};
+const emit = defineEmits(['update:modelValue', 'change']);
+/** 上传图片 */
+const uploadImg = async () => {
+    cropper.value.getCropBlob(async (data: any) => {
+        let formData = new FormData();
+        formData.append('file', data, options.fileName);
+        const res = await uploadFile(formData);
+        if (!res || res.code !== 200) return;
+        emit('update:modelValue', res.data.url);
+        emit('change', res.data.url);
+        open.value = false;
+    });
+};
+/** 实时预览 */
+const realTime = (data: any) => {
+    options.previews = data;
+};
+/** 关闭窗口 */
+const closeDialog = () => {
+    options.visible = false;
+};
+watch(
+    () => props.modelValue,
+    async (val) => {
+        if (val) {
+            options.img = val as string;
+        }
+    },
+    { deep: true, immediate: true }
+);
+watch(
+    () => props.name,
+    async (val) => {
+        if (val) {
+            options.name = val as string;
+        }
+    },
+    { deep: true, immediate: true }
+);
+</script>
+
+<style lang="scss" scoped>
+.user-info-head {
+    position: relative;
+    display: inline-block;
+    height: 120px;
+}
+
+.user-info-head:hover:after {
+    content: '+';
+    position: absolute;
+    left: 0;
+    right: 0;
+    top: 0;
+    bottom: 0;
+    color: #eee;
+    background: rgba(0, 0, 0, 0.5);
+    font-size: 24px;
+    font-style: normal;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    cursor: pointer;
+    line-height: 110px;
+    border-radius: 50%;
+}
+.icon-edit {
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    width: 20px;
+    height: 20px;
+    color: #fff;
+    line-height: 20px;
+    text-align: center;
+    font-size: 14px;
+    background: radial-gradient(70% 0% at 0% 0%, #0fd2a8 0%, #01e093 100%), #ffffff;
+    border-radius: 50%;
+}
+.head-img-box {
+    margin: auto;
+}
+</style>

+ 5 - 0
src/views/components/VueDrag.vue

@@ -0,0 +1,5 @@
+<template>
+    <div></div>
+</template>
+<script setup lang="ts" name="VueDrag">
+</script>

+ 21 - 0
src/views/components/index.ts

@@ -0,0 +1,21 @@
+/*
+ * @Description:
+ * @Version:
+ * @Author: 黄先伟
+ * @Date: 2024-02-06 09:05:33
+ */
+
+export { default as DescInfo } from './DescInfo.vue';
+export { default as DescItem } from './DescItem.vue';
+export { default as ImageViewer } from './ImageViewer.vue';
+export { default as DescItemTop } from './DescItemTop.vue';
+export { default as FileLook } from './FileLook.vue';
+export { default as MapContainer } from './MapContainer.vue';
+export { default as Breadcrumb } from './Breadcrumb.vue';
+export { default as VueDrag } from './VueDrag.vue'; // 选择地址
+export { default as AreaCascader } from './AreaCascader.vue'; // 行政区划选择
+export { default as UploadAvatar } from './UploadAvatar.vue'; // 头像选择器
+export { default as AreaView } from './AreaView.vue'; // 地址显示
+export { default as H5ModelLook } from './H5ModelLook.vue'; // 地址显示
+export { default as searchTabs } from './searchTabs.vue'; // tabs切换
+export { default as DateRange } from './DateRange.vue'; // 时间范围选择

+ 54 - 0
src/views/components/searchTabs.vue

@@ -0,0 +1,54 @@
+<template>
+    <div class="ridio-info d-flex f-w-w">
+        <!-- <div class="ridio-item f-12" @click="change('')" :class="{ checked: !activeName }">全部({{ total }})</div> -->
+        <template v-for="item in countList" :key="item.classType">
+            <div class="ridio-item f-12 f-w-5" @click="change(item.classType)" :class="{ checked: item.classType === activeName }">
+                <template v-if="isNum"> {{ item.className }}({{ item.classTypeNum }}) </template>
+                <template v-else> {{ item.className }} </template>
+            </div>
+        </template>
+    </div>
+</template>
+<script setup name="searchTabs" lang="ts">
+import { propTypes } from '@/utils/propTypes';
+const emit = defineEmits(['update:modelValue', 'change']);
+const activeName = ref('');
+const props = defineProps({
+    modelValue: propTypes.string.def(''),
+    countList: propTypes.any.def([]),
+    isNum: propTypes.bool.def(true)
+});
+const change = (event: any) => {
+    activeName.value = event;
+    emit('update:modelValue', event);
+    emit('change', event);
+};
+watch(
+    () => props.modelValue,
+    async (val) => {
+        if (val) {
+            activeName.value = val as string;
+        }
+    },
+    { deep: true, immediate: true }
+);
+</script>
+<style lang="scss" scoped>
+.ridio-info {
+    margin-left: -10px;
+    .ridio-item {
+        margin: 5px;
+        padding: 8px 10px;
+        line-height: 1.2;
+        border-radius: 15px;
+        user-select: none;
+        background-color: #f1f1f2;
+        cursor: pointer;
+
+        &.checked {
+            color: var(--el-color-primary);
+            background-color: var(--el-color-primary-light-9);
+        }
+    }
+}
+</style>

+ 14 - 0
src/views/components/types.ts

@@ -0,0 +1,14 @@
+export interface AnchorItem {
+    moduleName: string; // 模块名称
+    id?: string; // 模块id
+    status: string; // 模块状态
+    moduleType: string; // 模块类型
+    applicationId: string; // 申报书Id
+    approvalStatus: string; // 审批状态
+    approvalUser: string; // 审批人
+    approvalName: string; // 审批人姓名
+    approvalTime: string; // 审批人时间
+    approvalMsg: string; // 审批人信息
+    cpyid: string; // 企业Id
+    data?: any;
+}

+ 424 - 0
src/views/enterprise/recordCompany/index.vue

@@ -0,0 +1,424 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
+            :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div class="search" v-show="showSearch">
+                <el-form :model="queryParams" ref="queryFormRef" label-width="100px">
+                    <el-row :gutter="15">
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="企业名称" prop="cpyName">
+                                <el-input v-model="queryParams.cpyName" placeholder="请输入企业名称" clearable
+                                    @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="电话" prop="tel">
+                                <el-input v-model="queryParams.tel" placeholder="请输入电话" clearable
+                                    @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="信用代码" prop="creditCode">
+                                <el-input v-model="queryParams.creditCode" placeholder="请输入信用代码" clearable
+                                    @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="审核状态" prop="status">
+                                <el-select v-model="queryParams.status" style="width: 100%;" placeholder="请选择审核状态"
+                                    clearable>
+                                    <el-option v-for="dict in cpy_res_status" :key="dict.value" :label="dict.label"
+                                        :value="dict.value" />
+                                </el-select>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item>
+                                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </el-form>
+            </div>
+        </transition>
+        <el-card shadow="never">
+            <!-- <template #header>
+                <el-row :gutter="10" class="mb8">
+                    <el-col :span="1.5">
+                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['enterprise:recordCompany:add']">新增</el-button>
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button
+                            type="success"
+                            plain
+                            icon="Edit"
+                            :disabled="single"
+                            @click="handleUpdate()"
+                            v-hasPermi="['enterprise:recordCompany:edit']"
+                            >修改</el-button
+                        >
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button
+                            type="danger"
+                            plain
+                            icon="Delete"
+                            :disabled="multiple"
+                            @click="handleDelete()"
+                            v-hasPermi="['enterprise:recordCompany:remove']"
+                            >删除</el-button
+                        >
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['enterprise:recordCompany:export']"
+                            >导出</el-button
+                        >
+                    </el-col>
+                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+                </el-row>
+            </template> -->
+            <el-table v-loading="loading" :data="recordCompanyList" border @selection-change="handleSelectionChange">
+                <el-table-column type="selection" width="55" align="center" />
+                <el-table-column label="企业名称" align="center" prop="cpyName" />
+                <el-table-column label="企业logo" align="center" prop="license" width="100">
+                    <template #default="scope">
+                        <template v-if="scope.row.storePhoto && typeof scope.row.storePhoto === 'string'">
+                            <image-preview :src="scope.row.storePhoto" :width="50" :height="50" />
+                        </template>
+                        <template v-else>
+                            <span>暂无图片</span>
+                        </template>
+                    </template>
+                </el-table-column>
+                <el-table-column label="信用代码" align="center" prop="creditCode" />
+                <el-table-column label="营业执照" align="center" prop="license" width="100">
+                    <template #default="scope">
+                        <template v-if="scope.row.license && scope.row.license.url">
+                            <image-preview :src="scope.row.license.url" :width="50" :height="50" />
+                        </template>
+                    </template>
+                </el-table-column>
+                <el-table-column label="所在行政区" align="center" prop="adcdCode">
+                    <template #default="{ row }">
+                        <AreaView :value="row.adcdCode"></AreaView>
+                    </template>
+                </el-table-column>
+                <el-table-column label="合作伙伴" align="center" prop="partnerName" />
+                <el-table-column label="具体地址" align="center" prop="address" />
+                <el-table-column label="联系人姓名" align="center" prop="contactPerson" />
+                <el-table-column label="电话" align="center" prop="tel" />
+                <el-table-column label="创建时间" align="center" prop="createTime" show-overflow-tooltip width="110">
+                    <template #default="scope">
+                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="更新时间" align="center" prop="updateTime" show-overflow-tooltip width="110">
+                    <template #default="scope">
+                        <span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="审核状态" fixed="right" align="center" prop="status">
+                    <template #default="{ row }">
+                        <div>{{ selectDictLabel(cpy_res_status, row.status) }}</div>
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center" min-width="160" fixed="right"
+                    class-name="small-padding fixed-width">
+                    <template #default="scope">
+                        <el-tooltip content="修改" placement="top">
+                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
+                                v-hasPermi="['enterprise:recordCompany:edit']"></el-button>
+                        </el-tooltip>
+                        <el-tooltip content="删除" placement="top">
+                            <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)"
+                                v-hasPermi="['enterprise:recordCompany:remove']"></el-button>
+                        </el-tooltip>
+                        <template v-if="scope.row.status * 1 === 0">
+                            <el-tooltip content="审核通过" placement="top">
+                                <el-button link type="primary" icon="CircleCheck"
+                                    @click="handleApproval(scope.row, '1')"
+                                    v-hasPermi="['enterprise:recordCompany:edit']"></el-button>
+                            </el-tooltip>
+                            <el-tooltip content="审核不通过" placement="top">
+                                <el-button link type="danger" icon="CircleClose" @click="handleApproval(scope.row, '2')"
+                                    v-hasPermi="['enterprise:recordCompany:edit']"></el-button>
+                            </el-tooltip>
+                        </template>
+                    </template>
+                </el-table-column>
+            </el-table>
+
+            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+                v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+        <!-- 添加或修改企业备案信息对话框 -->
+        <el-dialog :close-on-click-modal="false" :title="dialog.title" v-model="dialog.visible" width="700px"
+            append-to-body>
+            <el-form ref="recordCompanyFormRef" :model="form" :rules="rules" label-width="auto">
+                <div class="mb20">
+                    <UploadAvatar title="企业logo" v-model="form.storePhoto"></UploadAvatar>
+                    <div class="t-a-c">企业logo</div>
+                </div>
+                <el-form-item prop="cpyName" label="企业名称">
+                    <el-input v-model="form.cpyName" class="base-input" placeholder="请填写企业名称" />
+                </el-form-item>
+                <el-form-item prop="cpyType" label="企业类型">
+                    <el-radio-group v-model="form.cpyType">
+                        <el-radio v-for="item in cpy_type" :key="item.value" :label="item.value" :value="item.value">{{
+                            item.label }}</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item prop="creditCode" label="统一社会信用代码">
+                    <el-input v-model="form.creditCode" maxlength="18" class="base-input"
+                        placeholder="请填写18位统一社会信用代码" />
+                </el-form-item>
+                <el-form-item prop="license" label="营业执照">
+                    <div class="flex1">
+                        <FileUpload v-model="form.license" :isFile="false" :span="20" :limit="1"
+                            :fileType="['png', 'jpg', 'jpeg']"></FileUpload>
+                    </div>
+                </el-form-item>
+                <el-form-item prop="adcdCode" label="所在行政区">
+                    <AreaCascader :zlevel="2" v-model="form.adcdCode"></AreaCascader>
+                </el-form-item>
+                <el-form-item prop="address" label="具体地址">
+                    <el-input v-model="form.address" class="base-input" placeholder="请填写区县以下的具体企业地址信息" />
+                </el-form-item>
+                <el-form-item prop="contactPerson" label="企业联系人">
+                    <el-input v-model="form.contactPerson" class="base-input" placeholder="请填写企业联系人姓名" />
+                </el-form-item>
+                <el-form-item prop="tel" label="企业联系电话">
+                    <el-input v-model="form.tel" class="base-input" maxlength="11" placeholder="请填写企业联系电话" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+                    <el-button @click="cancel">取 消</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="RecordCompany" lang="ts">
+import {
+    listRecordCompany,
+    getRecordCompany,
+    delRecordCompany,
+    addRecordCompany,
+    updateRecordCompany,
+    companyApproval
+} from '@/api/enterprise/recordCompany';
+import { RecordCompanyVO, RecordCompanyQuery, RecordCompanyForm } from '@/api/enterprise/recordCompany/types';
+import { AreaCascader, UploadAvatar, AreaView } from '@/views/components';
+import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
+import { Action } from 'element-plus';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { cpy_res_status, cpy_type } = toRefs<any>(proxy?.useDict('cpy_res_status', 'cpy_type'));
+const recordCompanyList = ref<RecordCompanyVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const recordCompanyFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+    visible: false,
+    title: ''
+});
+
+const initFormData: RecordCompanyForm = {
+    storePhoto: undefined,
+    cpyName: undefined,
+    creditCode: undefined,
+    license: undefined,
+    cpyType: undefined,
+    adcdCode: undefined,
+    address: undefined,
+    contactPerson: undefined,
+    tel: undefined
+};
+const data = reactive<PageData<RecordCompanyForm, RecordCompanyQuery>>({
+    form: { ...initFormData },
+    queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        cpyName: undefined,
+        tel: undefined,
+        creditCode: undefined,
+        status: '0'
+    },
+    rules: {
+        storePhoto: [{ required: true, trigger: 'blur', message: '请上传企业logo' }],
+        cpyName: [{ required: true, trigger: 'blur', message: '请填写企业名称' }],
+        creditCode: [{ required: true, trigger: 'blur', message: '请填写18位统一社会信用代码' }],
+        license: [{ required: true, trigger: 'blur', message: '请上传营业执照' }],
+        cpyType: [{ required: true, trigger: 'blur', message: '请选择结构类型' }],
+        adcdCode: [{ required: true, trigger: 'blur', message: '请选择所在行政区' }],
+        address: [{ required: true, trigger: 'blur', message: '请填写具体地址' }],
+        contactPerson: [{ required: true, trigger: 'blur', message: '请填写企业联系人姓名' }],
+        tel: [{ required: true, trigger: 'blur', message: '请填写企业联系电话' }]
+    }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+// 审批办理
+const handleApproval = async (row: any, res: string) => {
+    const { cpyName } = row;
+    if (res === '1') {
+        ElMessageBox.confirm('企业审核通过?', '提示', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            type: 'success',
+            icon: markRaw(CircleCheck)
+        })
+            .then(() => {
+                const params = {
+                    targetType: 'cpy',
+                    targetId: row.id,
+                    res
+                };
+                approvalAjax(params);
+            })
+            .catch(() => {
+                proxy?.$modal.msgWarning('取消审核');
+            });
+    } else {
+        ElMessageBox.prompt('企业审核不通过', '提示', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            inputPlaceholder: '不通过理由',
+            inputErrorMessage: '请填写不通过理由',
+            type: 'error',
+            icon: markRaw(CircleClose),
+            inputValidator: (value) => {
+                return value ? true : false
+            }
+        })
+            .then(({ value }) => {
+                const params = {
+                    targetType: 'cpy',
+                    targetId: row.id,
+                    res,
+                    msg: value
+                };
+                approvalAjax(params);
+            })
+            .catch(() => {
+                proxy?.$modal.msgWarning('取消审核');
+            });
+    }
+};
+const approvalAjax = async (params: any) => {
+    proxy?.$modal.loading('审核中...')
+    const res = await companyApproval(params).catch(() => { });
+    proxy?.$modal.closeLoading()
+    if (!res) return;
+    proxy?.$modal.msgSuccess('操作完成')
+    getList()
+};
+/** 查询企业备案信息列表 */
+const getList = async () => {
+    loading.value = true;
+    const res = await listRecordCompany(queryParams.value);
+    recordCompanyList.value = res.rows;
+    total.value = res.total;
+    loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+    reset();
+    dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+    form.value = { ...initFormData };
+    recordCompanyFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+    queryParams.value.pageNum = 1;
+    getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+    queryFormRef.value?.resetFields();
+    handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: RecordCompanyVO[]) => {
+    ids.value = selection.map((item) => item.id);
+    single.value = selection.length != 1;
+    multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+    reset();
+    dialog.visible = true;
+    dialog.title = '添加企业备案信息';
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: RecordCompanyVO) => {
+    reset();
+    const _id = row?.id || ids.value[0];
+    const res = await getRecordCompany(_id);
+    Object.assign(form.value, res.data);
+    dialog.visible = true;
+    dialog.title = '修改企业备案信息';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+    recordCompanyFormRef.value?.validate(async (valid: boolean) => {
+        if (valid) {
+            buttonLoading.value = true;
+            if (form.value.id) {
+                await updateRecordCompany(form.value).finally(() => (buttonLoading.value = false));
+            } else {
+                await addRecordCompany(form.value).finally(() => (buttonLoading.value = false));
+            }
+            proxy?.$modal.msgSuccess('修改成功');
+            dialog.visible = false;
+            await getList();
+        }
+    });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: RecordCompanyVO) => {
+    const _ids = row?.id || ids.value;
+    await proxy?.$modal.confirm('是否确认删除企业备案信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+    await delRecordCompany(_ids);
+    proxy?.$modal.msgSuccess('删除成功');
+    await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+    proxy?.download(
+        'enterprise/recordCompany/export',
+        {
+            ...queryParams.value
+        },
+        `recordCompany_${new Date().getTime()}.xlsx`
+    );
+};
+
+onMounted(() => {
+    getList();
+});
+</script>

+ 198 - 0
src/views/h5-custom/list/index.vue

@@ -0,0 +1,198 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div class="search" v-show="showSearch">
+                <el-form :model="queryParams" ref="queryFormRef" label-width="100px">
+                    <el-row :gutter="15">
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="模版类别" prop="tplType">
+                                <el-select v-model="queryParams.tplType" style="width: 100%;" placeholder="请选择审核状态" clearable>
+                                    <el-option v-for="dict in class_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                </el-select>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="企业名称" prop="cpyName">
+                                <el-input v-model="queryParams.cpyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="信用代码" prop="creditCode">
+                                <el-input v-model="queryParams.creditCode" placeholder="请输入信用代码" clearable @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="审核状态" prop="status">
+                                <el-select v-model="queryParams.status" style="width: 100%;" placeholder="请选择审核状态" clearable>
+                                    <el-option v-for="dict in cpy_res_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                </el-select>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item>
+                                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </el-form>
+            </div>
+        </transition>
+        <el-card shadow="never">
+            <el-table v-loading="loading" :data="list" border>
+                <el-table-column type="index" width="55" title="序号" align="center" />
+                <el-table-column label="模版类别" align="center">
+                    <template #default="{ row }">
+                        {{ selectDictLabel(class_type, row.tplType) || '-' }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="企业名称" min-width="150" align="center" prop="cpyName" />
+                <el-table-column label="统一社会信用代码" min-width="100" align="center" prop="creditCode" />
+                <el-table-column label="模版名称" min-width="150" align="center" prop="tplName" />
+                <el-table-column label="提交人" align="center" prop="lastModUserName" />
+                <el-table-column label="提交时间" align="center" prop="lastModTime" />
+                <el-table-column label="审核状态" align="center">
+                    <template #default="{ row }">
+                        {{ selectDictLabel(cpy_res_status, row.status) || '-' }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" width="300" fixed="right" class-name="small-padding fixed-width">
+                    <template #default="{ row }">
+                        <el-button @click="h5Preview(row)" text type="primary">预览</el-button>
+                        <template v-if="row.status === '0'">
+                            <el-button @click="handleApproval(row, '1')" text type="success">审核通过</el-button>
+                            <el-button @click="handleApproval(row, '2')" text type="danger">审核不通过</el-button>
+                        </template>
+                    </template>
+                </el-table-column>
+            </el-table>
+
+            <pagination
+                v-show="total > 0"
+                :total="total"
+                v-model:page="queryParams.pageNum"
+                v-model:limit="queryParams.pageSize"
+                @pagination="getList"
+            />
+        </el-card>
+    </div>
+    <H5ModelLook v-if="showH5Tem" v-model:show="showH5Tem" title="模版预览" :src="temSrc"></H5ModelLook>
+</template>
+
+<script setup name="H5-custom-list" lang="ts">
+import { h5TplApprove, h5TplList } from '@/api/h5-custom';
+import { colNoData } from '@/utils/models';
+import { H5ModelLook } from '@/views/components';
+
+import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
+import { getCurrentInstance, reactive, ref, toRefs } from 'vue';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { class_type, cpy_res_status } = toRefs<any>(proxy?.useDict('class_type', 'cpy_res_status'));
+const list = ref<any[]>([]);
+const showH5Tem = ref(false);
+const temSrc = ref('');
+const loading = ref(true);
+const showSearch = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+
+const data = reactive<any>({
+    queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        cpyName: undefined,
+        tplType: undefined,
+        tel: undefined,
+        creditCode: undefined,
+        status: '0'
+    },
+});
+const { queryParams, form } = toRefs(data);
+// 模版预览
+const h5Preview = (row: any) => {
+    const { appid } = row
+    const mapId: any = {
+        '1838028510242902017': 'a/',
+        '1785120816244535298': ''
+    }
+    temSrc.value = import.meta.env.VITE_H5_URL + (mapId[appid] || '') + 'pages/index/tem-preview?id=' + row.id + '&myl=1&state=' + new Date().getTime();
+    showH5Tem.value = true;
+};
+// 审批办理
+const handleApproval = async (row: any, res: string) => {
+    const { cpyName } = row;
+    if (res === '1') {
+        ElMessageBox.confirm('模版审核通过?', '提示', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            type: 'success',
+            icon: markRaw(CircleCheck)
+        })
+            .then(() => {
+                const params = {
+                    targetId: row.id,
+                    res
+                };
+                approvalAjax(params);
+            })
+            .catch(() => {
+                proxy?.$modal.msgWarning('取消审核');
+            });
+    } else {
+        ElMessageBox.prompt('模版审核不通过', '提示', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            inputPlaceholder: '不通过理由',
+            inputErrorMessage: '请填写不通过理由',
+            type: 'error',
+            icon: markRaw(CircleClose),
+            inputValidator: (value) => {
+                return value ? true : false;
+            }
+        })
+            .then(({ value }) => {
+                const params = {
+                    targetId: row.id,
+                    res,
+                    msg: value
+                };
+                approvalAjax(params);
+            })
+            .catch(() => {
+                proxy?.$modal.msgWarning('取消审核');
+            });
+    }
+};
+const approvalAjax = async (params: any) => {
+    proxy?.$modal.loading('审核中...');
+    const res = await h5TplApprove(params).catch(() => {});
+    proxy?.$modal.closeLoading();
+    if (!res) return;
+    proxy?.$modal.msgSuccess('操作完成');
+    getList();
+};
+/** 查询企业备案信息列表 */
+const getList = async () => {
+    loading.value = true;
+    const res = await h5TplList(queryParams.value);
+    list.value = res.rows;
+    total.value = res.total;
+    loading.value = false;
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+    queryParams.value.pageNum = 1;
+    getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+    queryFormRef.value?.resetFields();
+    handleQuery();
+};
+onMounted(() => {
+    getList();
+});
+</script>

+ 1 - 1
src/views/leader/declaration-detail/index.vue

@@ -42,7 +42,7 @@
                     <div class="info-title f-w-5 mb-10">标准应用产品图</div>
                     <div class="imgout">
                         <div v-for="(item,index) in form?.imgs" :key="index">
-                            <img :src="item" style="height: 300px;width: 300px;object-fit: cover;" />
+                            <el-image :src="item" style="height: 200px;width: 200px;" fit="cover" :preview-src-list="form?.imgs" :initial-index="index"/>
                         </div>
                     </div>
                     <el-divider />

+ 1 - 0
src/views/leader/declaration-record/index.vue

@@ -79,6 +79,7 @@ const initFormData = {};
 const data = reactive<any>({
     form: { ...initFormData },
     queryParams: {
+        status:"0",
         pageNum: 1,
         pageSize: 10,
         res: '0',

+ 453 - 0
src/views/permission/application/index.vue

@@ -0,0 +1,453 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div class="search" v-show="showSearch">
+                <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+                    <el-form-item label="应用名称" prop="applicationName">
+                        <el-input
+                            v-model="queryParams.applicationName"
+                            placeholder="请输入应用名称"
+                            clearable
+                            style="width: 240px"
+                            @keyup.enter="handleQuery"
+                        />
+                    </el-form-item>
+                    <el-form-item label="图标" prop="icon">
+                        <el-input v-model="queryParams.icon" placeholder="请输入图标" clearable style="width: 240px" @keyup.enter="handleQuery" />
+                    </el-form-item>
+                    <el-form-item label="跳转地址" prop="url">
+                        <el-input v-model="queryParams.url" placeholder="请输入跳转地址" clearable style="width: 240px" @keyup.enter="handleQuery" />
+                    </el-form-item>
+                    <el-form-item>
+                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </transition>
+
+        <el-tabs v-model="activeTab" style="padding: 5px;">
+            <el-tab-pane label="千寻应用" name="tab1">
+                <el-card shadow="never">
+                    <template #header>
+                        <el-row :gutter="10" class="mb8">
+                            <el-col :span="1.5">
+                                <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['smarttrace:application:add']"
+                                    >新增</el-button
+                                >
+                            </el-col>
+                            <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+                        </el-row>
+                    </template>
+
+                    <el-table v-loading="loading" :data="applicationList" border>
+                        <el-table-column type="index" label="序号" width="55" align="center" />
+                        <el-table-column label="应用名称" align="center" prop="applicationName" />
+                        <el-table-column label="图标" align="center" prop="icon">
+                            <template #default="{ row }">
+                                <ImagePreview :src="row.icon" style="width: 50px;height: 50px;"></ImagePreview>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="背景" align="center" prop="bgUrl">
+                            <template #default="{ row }">
+                                <ImagePreview :src="row.bgUrl" style="width: 50px;height: 50px;"></ImagePreview>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="跳转地址" align="center" prop="url" />
+                        <el-table-column label="应用类型" align="center" prop="type">
+                            <template #default="{ row }">
+                                <span>{{ selectDictLabel(application_type, row.type) }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="前置条件" width="200">
+                            <template #default="{ row }">
+                                <div v-for="item in row.precondition" style="display: flex;">
+                                    <div>
+                                        <dict-tag :options="enterprise_type" :value="item.cpyType" />
+                                    </div>
+                                    -
+                                    <div>
+                                        <dict-tag :options="industry_type" :value="item.industryType" />
+                                    </div>
+                                </div>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="状态" align="center" width="180" prop="status">
+                            <template #default="{ row }">
+                                <el-switch
+                                    :value="row.status"
+                                    active-value="1"
+                                    @change="changeStatus($event, row.id)"
+                                    inactive-value="0"
+                                    active-text="启用"
+                                    inactive-text="未启用"
+                                />
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="备注" align="center" prop="remark" />
+                        <el-table-column label="应用ID" align="center" prop="id" />
+                        <el-table-column label="创建时间" align="center" prop="createTime" width="120">
+                            <template #default="scope">
+                                <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+                            </template>
+                        </el-table-column>
+
+                        <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
+                            <template #default="scope">
+                                <el-tooltip content="编辑" placement="top">
+                                    <el-button
+                                        link
+                                        type="primary"
+                                        icon="Edit"
+                                        @click="handleEdit(scope.row)"
+                                        v-hasPermi="['smarttrace:application:remove']"
+                                    ></el-button>
+                                </el-tooltip>
+                                <el-tooltip content="删除" placement="top">
+                                    <el-button
+                                        link
+                                        type="primary"
+                                        icon="Delete"
+                                        @click="handleDelete(scope.row)"
+                                        v-hasPermi="['smarttrace:application:remove']"
+                                    ></el-button>
+                                </el-tooltip>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                    <pagination
+                        v-show="total > 0"
+                        :total="total"
+                        v-model:page="queryParams.pageNum"
+                        v-model:limit="queryParams.pageSize"
+                        @pagination="getList"
+                    />
+                </el-card>
+            </el-tab-pane>
+            <el-tab-pane label="合作伙伴应用" name="tab2">
+                <el-table v-loading="loading" :data="applicationList2" border>
+                    <el-table-column type="index" width="55" align="center" label="序号" />
+                    <el-table-column label="应用名称" align="center" prop="applicationName" />
+                    <el-table-column label="图标" align="center" prop="icon">
+                        <template #default="{ row }">
+                            <ImagePreview :src="row.icon" style="width: 50px;height: 50px;"></ImagePreview>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="背景" align="center" prop="bgUrl">
+                        <template #default="{ row }">
+                            <ImagePreview :src="row.bgUrl" style="width: 50px;height: 50px;"></ImagePreview>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="跳转地址" align="center" prop="url" />
+                    <el-table-column label="应用类型" align="center" prop="type">
+                        <template #default="{ row }">
+                            <span>{{ selectDictLabel(application_type, row.type) }}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="状态" align="center" width="180" prop="status">
+                        <template #default="{ row }">
+                            <el-switch :value="row.status" active-value="1" inactive-value="0" disabled active-text="启用" inactive-text="未启用" />
+                        </template>
+                    </el-table-column>
+                    <el-table-column label="备注" align="center" prop="remark" />
+                    <el-table-column label="应用ID" align="center" prop="id" />
+                    <el-table-column label="授权开始日期" align="center" prop="startAt" />
+                    <el-table-column label="授权结束日期" align="center" prop="endAt" />
+                    <el-table-column label="千寻应用" align="center" prop="originName" />
+                    <el-table-column label="合作伙伴" align="center" prop="partner">
+                        <template #default="{ row }"> </template>
+                    </el-table-column>
+                    <el-table-column label="创建时间" align="center" prop="createTime" width="120">
+                        <template #default="scope">
+                            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+                        </template>
+                    </el-table-column>
+                </el-table>
+                <pagination
+                    v-show="total > 0"
+                    :total="total"
+                    v-model:page="queryParams.pageNum"
+                    v-model:limit="queryParams.pageSize"
+                    @pagination="getList2"
+                />
+            </el-tab-pane>
+        </el-tabs>
+        <!-- 添加或修改应用信息对话框 -->
+        <el-dialog :close-on-click-modal="false" :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body>
+            <el-form ref="applicationFormRef" :model="form" :rules="rules" label-width="80px">
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item label="应用名称" prop="applicationName">
+                            <el-input v-model="form.applicationName" placeholder="请输入应用名称" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="应用类型" prop="type">
+                            <el-select v-model="form.type" style="width: 100%;" placeholder="请选择应用类型" clearable>
+                                <el-option v-for="dict in application_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item label="图标" prop="icon">
+                            <div>
+                                <UploadAvatar title="应用图标" v-model="form.icon"></UploadAvatar>
+                            </div>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="背景" prop="bgUrl">
+                            <div class="flex1">
+                                <PhotoUpload v-model="form.bgUrl"></PhotoUpload>
+                            </div>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-form-item label="排序" prop="sort">
+                    <el-input-number v-model="form.sort" placeholder="请输入排序" />
+                </el-form-item>
+                <el-form-item label="按钮配置" prop="btnConf">
+                    <el-input v-model="form.btnConf" placeholder="请输入按钮配置" />
+                </el-form-item>
+                <el-form-item label="跳转地址" prop="url">
+                    <el-input v-model="form.url" placeholder="请输入跳转地址" />
+                </el-form-item>
+                <el-form-item label="备注" prop="remark">
+                    <el-input v-model="form.remark" placeholder="请输入备注" />
+                </el-form-item>
+                <el-divider>前置条件(任意一个)</el-divider>
+                <div class="cpy-container" v-loading="loading">
+                    <div class="cpy-item" v-for="(item, index) in form.precondition" :key="index">
+                        <el-form-item
+                            label="企业类型"
+                            :prop="`precondition.${index}.cpyType`"
+                            :rules="{ required: true, message: '企业类型不能为空', trigger: 'blur' }"
+                        >
+                            <el-select v-model="item.cpyType" placeholder="企业类型" clearable>
+                                <el-option v-for="dict in enterprise_type" :label="dict.label" :value="dict.value" :key="dict.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item
+                            label="行业类别"
+                            :prop="`precondition.${index}.industryType`"
+                            :rules="{ required: true, message: '行业类别不能为空', trigger: 'blur' }"
+                            clearable
+                        >
+                            <el-select v-model="item.industryType" placeholder="行业类别">
+                                <el-option v-for="dict in industry_type" :label="dict.label" :value="dict.value" :key="dict.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <el-button type="text" icon="remove" @click="handleRemovePrecondition(index)"></el-button>
+                    </div>
+                </div>
+                <span v-show="form.precondition.length == 0">无需前置条件</span>
+                <div style="display: flex;">
+                    <el-button type="primary" style="flex:1" @click="handleAddPrecondition">添加条件</el-button>
+                </div>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+                    <el-button @click="cancel">取 消</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="Application" lang="ts">
+import {
+    listApplicationQx,
+    listApplicationOther,
+    getApplication,
+    delApplication,
+    addApplication,
+    updateApplication,
+    ApplicationOnshelf,
+    ApplicationLeaveshelf
+} from '@/api/permission/application';
+import { ApplicationVO, ApplicationQuery, ApplicationForm } from '@/api/permission/application/types';
+import { UploadAvatar } from '@/views/components';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { application_type, enterprise_type, industry_type } = toRefs<any>(proxy?.useDict('application_type', 'industry_type', 'enterprise_type'));
+const applicationList = ref<ApplicationVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const applicationFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+    visible: false,
+    title: ''
+});
+
+const initFormData = (): ApplicationForm => ({
+    id: undefined,
+    applicationName: undefined,
+    icon: undefined,
+    url: undefined,
+    type: undefined,
+    remark: undefined,
+    keyInfo: {},
+    sort:0,
+    btnConf: undefined,
+    precondition: []
+});
+const data = reactive<PageData<ApplicationForm, ApplicationQuery>>({
+    form: initFormData(),
+    queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        applicationName: undefined,
+        type: undefined,
+        status: undefined,
+        params: {}
+    },
+    rules: {
+        applicationName: [{ required: true, message: '应用名称不能为空', trigger: 'blur' }],
+        icon: [{ required: true, message: '图标不能为空', trigger: 'blur' }],
+        url: [{ required: true, message: '跳转地址不能为空', trigger: 'blur' }],
+        type: [{ required: true, message: '应用类型不能为空', trigger: 'change' }]
+    }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+/** 启用和未启用开关 */
+const changeStatus = async (event: string, id: string) => {
+    let res = null;
+    loading.value = true;
+    if (+event) {
+        res = await ApplicationOnshelf(id);
+    } else {
+        res = await ApplicationLeaveshelf(id);
+    }
+    getList();
+};
+/** 查询应用信息列表 */
+const getList = async () => {
+    loading.value = true;
+    const res = await listApplicationQx(queryParams.value);
+    applicationList.value = res.rows;
+    total.value = res.total;
+    loading.value = false;
+};
+
+/** 取消按钮 */
+const cancel = () => {
+    reset();
+    dialog.visible = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+    form.value = initFormData();
+    applicationFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+    queryParams.value.pageNum = 1;
+    queryParams2.value.pageNum = 1;
+    getList();
+    getList2();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+    queryFormRef.value?.resetFields();
+    handleQuery();
+};
+/** 添加前置条件 */
+const handleAddPrecondition = () => {
+    form.value.precondition.push({ cpyType: undefined, industryType: undefined });
+};
+const handleRemovePrecondition = (index: number) => {
+    form.value.precondition.splice(index, 1);
+};
+/** 新增按钮操作 */
+const handleAdd = () => {
+    reset();
+    dialog.visible = true;
+    dialog.title = '添加应用信息';
+};
+const handleEdit = (row: any) => {
+    reset();
+    Object.assign(form.value, row);
+    dialog.visible = true;
+    dialog.title = '修改应用信息';
+};
+
+/** 提交按钮 */
+const submitForm = () => {
+    applicationFormRef.value?.validate(async (valid: boolean) => {
+        if (valid) {
+            buttonLoading.value = true;
+            if (form.value.id) {
+                await updateApplication(form.value).finally(() => (buttonLoading.value = false));
+            } else {
+                await addApplication(form.value).finally(() => (buttonLoading.value = false));
+            }
+            proxy?.$modal.msgSuccess('修改成功');
+            dialog.visible = false;
+            await getList();
+        }
+    });
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ApplicationVO) => {
+    const _ids = row?.id || ids.value;
+    await proxy?.$modal.confirm('是否确认删除应用信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+    await delApplication(_ids);
+    proxy?.$modal.msgSuccess('删除成功');
+    await getList();
+};
+/**合作伙伴应用 */
+const activeTab = ref('tab1');
+const applicationList2 = ref<ApplicationVO[]>([]);
+const queryParams2 = ref<ApplicationQuery>({
+    pageNum: 1,
+    pageSize: 10,
+    applicationName: undefined,
+    type: undefined,
+    status: undefined
+});
+watch(queryParams, (newValue) => {
+    queryParams2.value.applicationName = newValue.applicationName;
+    queryParams2.value.type = newValue.type;
+    queryParams2.value.status = newValue.status;
+});
+const total2 = ref(0);
+const loading2 = ref(false);
+/** 查询合作伙伴应用信息列表 */
+const getList2 = async () => {
+    loading2.value = true;
+    const res = await listApplicationOther(queryParams2.value);
+    applicationList2.value = res.rows;
+    total2.value = res.total;
+    loading2.value = false;
+};
+
+onMounted(() => {
+    getList();
+    getList2();
+});
+</script>
+<style scoped>
+.cpy-container {
+    margin-top: 20px;
+    margin-bottom: 20px;
+
+    .cpy-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: baseline;
+    }
+}
+</style>

+ 558 - 0
src/views/permission/partner/index.vue

@@ -0,0 +1,558 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
+      :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div class="search" v-show="showSearch">
+        <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="108px">
+          <el-form-item label="合作伙伴名称" prop="partnerName">
+            <el-input v-model="queryParams.partnerName" placeholder="请输入合作伙伴名称" clearable style="width: 240px"
+              @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item label="合作伙伴编码" prop="partnerCode">
+            <el-input v-model="queryParams.partnerCode" placeholder="请输入合作伙伴编码" clearable style="width: 240px"
+              @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </transition>
+    <el-tabs v-model="activeTab" style="padding: 5px;">
+      <el-tab-pane label="合作伙伴" name="tab1">
+        <el-card shadow="never">
+          <template #header>
+            <el-row :gutter="10" class="mb8">
+              <el-col :span="1.5">
+                <el-button type="primary" plain icon="Plus" @click="handleAdd"
+                  v-hasPermi="['smarttrace:partner:add']">新增</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
+                  v-hasPermi="['smarttrace:partner:edit']">修改</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
+                  v-hasPermi="['smarttrace:partner:remove']">删除</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button type="warning" plain icon="Download" @click="handleExport"
+                  v-hasPermi="['smarttrace:partner:export']">导出</el-button>
+              </el-col>
+              <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+            </el-row>
+          </template>
+
+          <el-table v-loading="loading" :data="partnerList">
+            <el-table-column type="index" label="序号" width="55" align="center" />
+            <el-table-column label="合作伙伴名称" align="center" prop="partnerName" />
+            <el-table-column label="合作伙伴编码" align="center" prop="partnerCode" />
+            <el-table-column label="备注" align="center" prop="remark" />
+            <el-table-column label="已授权应用" align="center" prop="apps">
+              <template #default="scope">
+                <el-button type="text" @click="viewApps(scope.row)">查看({{ scope.row.appCount || 0 }})</el-button>
+              </template>
+            </el-table-column>
+            <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+              <template #default="scope">
+                <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+              <template #default="scope">
+                <el-tooltip content="修改" placement="top">
+                  <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
+                    v-hasPermi="['smarttrace:partner:edit']"></el-button>
+                </el-tooltip>
+                <el-tooltip content="删除" placement="top">
+                  <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
+                    v-hasPermi="['smarttrace:partner:remove']"></el-button>
+                </el-tooltip>
+              </template>
+            </el-table-column>
+          </el-table>
+
+          <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
+            v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+      </el-tab-pane>
+      <el-tab-pane label="授权应用" name="tab2" disabled>
+        <el-card shadow="never">
+          <template #header>
+            <el-row :gutter="10" class="mb8">
+              <el-col :span="1.5">
+                <el-button type="primary" plain icon="Plus" @click="handleAddApp"
+                  v-hasPermi="['smarttrace:partner:add']">新增应用授权</el-button>
+              </el-col>
+              <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+            </el-row>
+          </template>
+          <el-table v-loading="loading" :data="applicationList" border>
+            <el-table-column type="index" label="序号" width="55" align="center" />
+            <el-table-column label="应用名称" align="center" prop="applicationName" />
+            <el-table-column label="图标" align="center" prop="icon">
+              <template #default="{ row }">
+                <ImagePreview :src="row.icon"></ImagePreview>
+              </template>
+            </el-table-column>
+            <el-table-column label="背景" align="center" prop="bgUrl">
+              <template #default="{ row }">
+                <ImagePreview :src="row.bgUrl"></ImagePreview>
+              </template>
+            </el-table-column>
+            <el-table-column label="跳转地址" align="center" prop="url" />
+            <el-table-column label="应用类型" align="center" prop="type">
+              <template #default="{ row }">
+                <dict-tag :options="application_type" :value="row.type"></dict-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="前置条件" width="200">
+              <template #default="{ row }">
+                <div v-for="item in row.precondition" style="display: flex;">
+                  <div>
+                    <dict-tag :options="enterprise_type" :value="item.cpyType" />
+                  </div>
+                  -
+                  <div>
+                    <dict-tag :options="industry_type" :value="item.industryType" />
+                  </div>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="状态" align="center" width="180" prop="status">
+              <template #default="{ row }">
+                <el-switch :value="row.status" active-value="1" @change="changeStatus($event, row.id)"
+                  inactive-value="0" active-text="启用" inactive-text="未启用" />
+              </template>
+            </el-table-column>
+            <el-table-column label="授权开始日期" align="center" prop="startAt" />
+            <el-table-column label="授权结束日期" align="center" prop="endAt" />
+            <el-table-column label="备注" align="center" prop="remark" />
+            <el-table-column label="应用ID" align="center" prop="id" />
+            <el-table-column label="创建时间" align="center" prop="createTime" width="120">
+              <template #default="scope">
+                <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
+              <template #default="scope">
+                <el-tooltip content="编辑" placement="top">
+                  <el-button link type="primary" icon="Edit" @click="handleEdit(scope.row)"
+                    v-hasPermi="['smarttrace:application:edit']"></el-button>
+                </el-tooltip>
+                <el-tooltip content="查看" placement="top">
+                  <el-button link type="primary" icon="View" @click="handleView(scope.row)"
+                    v-hasPermi="['smarttrace:application:edit']"></el-button>
+                </el-tooltip>
+                <el-tooltip content="删除" placement="top">
+                  <el-button link type="primary" icon="Delete" @click="handleDeleteApp(scope.row)"
+                    v-hasPermi="['smarttrace:application:remove']"></el-button>
+                </el-tooltip>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+      </el-tab-pane>
+    </el-tabs>
+    <!-- 添加或修改合作伙伴信息对话框 -->
+    <el-dialog :close-on-click-modal="false" :title="dialog.title" v-model="dialog.visible" width="500px"
+      append-to-body>
+      <el-form ref="partnerFormRef" :model="form" :rules="rules" label-width="108px">
+        <el-form-item label="合作伙伴名称" prop="partnerName">
+          <el-input v-model="form.partnerName" placeholder="请输入合作伙伴名称" />
+        </el-form-item>
+        <el-form-item label="合作伙伴编码" prop="partnerCode">
+          <el-input v-model="form.partnerCode" placeholder="请输入合作伙伴编码" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+    <!-- 添加应用-->
+    <el-dialog :close-on-click-modal="false" title="合作伙伴应用授权" v-model="appAddvisible" width="600px" append-to-body>
+      <el-form ref="appAddFormRef" :model="appAddForm" :rules="appAddRules" label-width="108px"
+        :disabled="appAddDisabled">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="原始应用" prop="originId">
+              <el-select v-model="appAddForm.originId" style="width: 100%;" placeholder="请选择原始应用">
+                <el-option v-for="app in originApps" :key="app.id" :label="app.applicationName"
+                  :value="(app.id as number)" @click.native="handleOriginChange(app)" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="应用类型" prop="type">
+              <el-select v-model="appAddForm.type" style="width: 100%;" placeholder="请选择应用类型" disabled>
+                <el-option v-for="dict in application_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="应用名称" prop="applicationName">
+          <el-input v-model="appAddForm.applicationName" placeholder="请输入应用名称" />
+        </el-form-item>
+        <el-form-item label="跳转地址" prop="url">
+          <el-input v-model="appAddForm.url" placeholder="跳转地址" />
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="图标" prop="icon">
+              <div>
+                <UploadAvatar title="应用图标" v-model="appAddForm.icon"></UploadAvatar>
+              </div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="背景" prop="bgUrl">
+              <PhotoUpload v-model="appAddForm.bgUrl"></PhotoUpload>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="按钮颜色" prop="btnConf">
+              <el-input v-model="appAddForm.btnConf"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="授权开始日期" prop="startAt">
+              <el-date-picker v-model="appAddForm.startAt" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="授权结束日期" prop="endAt">
+              <el-date-picker v-model="appAddForm.endAt" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="appAddForm.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="按钮配置" prop="btnConf">
+          <el-input v-model="appAddForm.btnConf" placeholder="请输入按钮配置" />
+        </el-form-item>
+        <el-divider>前置条件(任意一个)</el-divider>
+        <div class="cpy-container" v-loading="loading">
+          <div class="cpy-item" v-for="(item, index) in appAddForm.precondition">
+            <el-form-item label="企业类型" :prop="`precondition.${index}.cpyType`"
+              :rules="{ required: true, message: '企业类型不能为空', trigger: 'blur' }">
+              <el-select v-model="item.cpyType" placeholder="企业类型">
+                <el-option v-for="dict in enterprise_type" :label="dict.label" :value="dict.value"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="行业类别" :prop="`precondition.${index}.industryType`"
+              :rules="{ required: true, message: '行业类别不能为空', trigger: 'blur' }">
+              <el-select v-model="item.industryType" placeholder="行业类别">
+                <el-option v-for="dict in industry_type" :label="dict.label" :value="dict.value"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-button type="text" icon="remove" @click="handleRemovePrecondition(index)"></el-button>
+          </div>
+        </div>
+        <span v-show="appAddForm.precondition.length == 0">无需前置条件</span>
+        <div style="display: flex;">
+          <el-button type="primary" style="flex:1" @click="handleAddPrecondition">添加条件</el-button>
+        </div>
+        <el-divider>密钥信息</el-divider>
+        <el-form-item label="应用私钥" prop="partnerPriKey">
+          <el-input v-model="appAddForm.keyInfo.partnerPriKey" placeholder="请输入应用私钥" />
+        </el-form-item>
+        <el-form-item label="应用公钥" prop="partnerPubKey">
+          <el-input v-model="appAddForm.keyInfo.partnerPubKey" placeholder="请输入应用公钥" />
+        </el-form-item>
+        <el-form-item label="小程序appid" prop="appid">
+          <el-input v-model="appAddForm.keyInfo.appid" placeholder="请输入小程序appid" />
+        </el-form-item>
+        <el-form-item label="小程序secret" prop="secret">
+          <el-input v-model="appAddForm.keyInfo.secret" placeholder="请输入小程序secret" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitAppAddForm">确 定</el-button>
+          <el-button @click="cancelAppAdd">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Partner" lang="ts">
+import { listPartner, getPartner, delPartner, addPartner, updatePartner } from '@/api/permission/partner';
+import { listApplicationOther, listApplicationQx, addApplication, ApplicationOnshelf, ApplicationLeaveshelf, delApplication, updateApplication } from "@/api/permission/application";
+import { PartnerVO, PartnerQuery, PartnerForm } from '@/api/permission/partner/types';
+import { ApplicationVO, ApplicationForm } from "@/api/permission/application/types";
+import { parseTime } from '@/utils/ruoyi'
+import { UploadAvatar } from '@/views/components';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const partnerList = ref<PartnerVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const { application_type, enterprise_type, industry_type } = toRefs<any>(proxy?.useDict('application_type', 'industry_type', 'enterprise_type'))
+const queryFormRef = ref<ElFormInstance>();
+const partnerFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: PartnerForm = {
+  id: undefined,
+  partnerName: undefined,
+  partnerCode: undefined,
+  key: undefined,
+  startAt: undefined,
+  endAt: undefined,
+  status: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<PartnerForm, PartnerQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    partnerName: undefined,
+    partnerCode: undefined,
+    key: undefined,
+    startAt: undefined,
+    endAt: undefined,
+    status: undefined,
+    params: {
+    }
+  },
+  rules: {
+    id: [
+      { required: true, message: "ID不能为空", trigger: "blur" }
+    ],
+    partnerName: [
+      { required: true, message: "合作伙伴名称不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询合作伙伴信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listPartner(queryParams.value);
+  partnerList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  partnerFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加合作伙伴信息";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: PartnerVO) => {
+  reset();
+  const _id = row?.id as number
+  const res = await getPartner(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改合作伙伴信息";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  partnerFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updatePartner(form.value).finally(() => buttonLoading.value = false);
+      } else {
+        await addPartner(form.value).finally(() => buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("修改成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: PartnerVO) => {
+  const _ids = row?.id as number
+  await proxy?.$modal.confirm('是否确认删除合作伙伴信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delPartner(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('permission/partner/export', {
+    ...queryParams.value
+  }, `partner_${new Date().getTime()}.xlsx`)
+}
+const activeTab = ref('tab1')
+/** tab2 */
+const applicationList = ref<ApplicationVO[]>([])
+const originApps = ref<ApplicationVO[]>([])
+const partnerId = ref<number | undefined>(undefined)
+const appAddDisabled = ref(false)
+const viewApps = async (row: any) => {
+  partnerId.value = row.id
+  loading.value = true
+  const res = await listApplicationOther({ partnerId: row.id || '', pageNum: 1, pageSize: 100 }).finally(() => loading.value = false)
+  applicationList.value = res.rows
+  activeTab.value = 'tab2'
+}
+
+const handleDeleteApp = async (row: ApplicationVO) => {
+  await proxy?.$modal.confirm('是否确认删除应用?').finally(() => loading.value = false);
+  await delApplication(row.id || '');
+  proxy?.$modal.msgSuccess("删除成功");
+  viewApps({ id: partnerId.value })
+}
+const changeStatus = async (event: string, id: string) => {
+  loading.value = true;
+  const fun = +event ? ApplicationOnshelf(id) : ApplicationLeaveshelf(id)
+  await fun
+  viewApps({ id: partnerId.value })
+}
+/**
+ * 弹框相关
+ */
+const initAppAddForm = (): ApplicationForm => ({
+  id: undefined,
+  applicationName: undefined,
+  icon: undefined,
+  url: undefined,
+  type: undefined,
+  remark: undefined,
+  startAt: new Date(),
+  endAt: undefined,
+  originId: undefined,
+  partnerId: partnerId.value,
+  keyInfo: {},
+  precondition: []
+})
+const appAddForm = ref(initAppAddForm())
+const appAddFormRef = ref<ElFormInstance>();
+const appAddRules = {
+  applicationName: [{ required: true, message: "应用名称不能为空", trigger: "blur" }],
+  originId: [{ required: true, message: "原始应用不能为空", trigger: "blur" }],
+  type: [{ required: true, message: "应用名称不能为空", trigger: "blur" }],
+  partnerId: [{ required: true, message: "合作伙伴不能为空", trigger: "blur" }],
+  startAt: [{ required: true, message: "开始日期不能为空", trigger: "blur" }],
+}
+/** 添加前置条件 */
+const handleAddPrecondition = () => {
+  appAddForm.value.precondition.push({ cpyType: '1', industryType: '1' })
+}
+const handleRemovePrecondition = (index: number) => {
+  appAddForm.value.precondition.splice(index, 1)
+}
+const appAddvisible = ref(false)
+const resetAppAdd = () => {
+  appAddDisabled.value = false
+  appAddForm.value = initAppAddForm()
+}
+const cancelAppAdd = () => {
+  appAddvisible.value = false
+}
+const handleAddApp = () => {
+  resetAppAdd()
+  appAddvisible.value = true
+}
+const handleEdit = (row: ApplicationVO) => {
+  resetAppAdd()
+  Object.assign(appAddForm.value, row)
+  appAddvisible.value = true
+}
+const handleView = (row: ApplicationVO) => {
+  resetAppAdd()
+  appAddDisabled.value = true
+  Object.assign(appAddForm.value, row)
+  appAddvisible.value = true
+}
+const submitAppAddForm = async () => {
+  const valid = await appAddFormRef.value?.validate()
+  if (valid) {
+    buttonLoading.value = true
+    const fun = appAddForm.value.id ? updateApplication(appAddForm.value) : addApplication(appAddForm.value)
+    await fun.finally(() => buttonLoading.value = false)
+    appAddvisible.value = false
+    proxy?.$modal.alert("操作成功")
+    viewApps({ id: appAddForm.value.partnerId })
+  }
+}
+const loadApps = async () => {
+  const res = await listApplicationQx({ pageNum: 1, pageSize: 100 });
+  originApps.value = res.rows;
+}
+const diffApps = computed(() => {
+  return originApps.value.filter(x => !applicationList.value.map(o => o.originId).includes(x.id as number))
+})
+const handleOriginChange = (app: ApplicationVO) => {
+  appAddForm.value.applicationName = app.applicationName
+  appAddForm.value.type = app.type
+  appAddForm.value.icon = app.icon
+  appAddForm.value.bgUrl = app.bgUrl
+  appAddForm.value.precondition = app.precondition
+}
+onMounted(() => {
+  getList();
+  loadApps();
+
+});
+</script>
+<style scoped>
+.cpy-container {
+  margin-top: 20px;
+  margin-bottom: 20px;
+
+  .cpy-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+  }
+}
+</style>

+ 187 - 0
src/views/settled/control/index.vue

@@ -0,0 +1,187 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div class="search" v-show="showSearch">
+                <el-form :model="queryParams" ref="queryFormRef" label-width="100px">
+                    <el-row :gutter="15">
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="企业名称" prop="cpyName">
+                                <el-input v-model="queryParams.cpyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="电话" prop="tel">
+                                <el-input v-model="queryParams.tel" placeholder="请输入电话" clearable @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item label="信用代码" prop="creditCode">
+                                <el-input v-model="queryParams.creditCode" placeholder="请输入信用代码" clearable @keyup.enter="handleQuery" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="6" :lg="8" :sm="12">
+                            <el-form-item>
+                                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </el-form>
+            </div>
+        </transition>
+        <el-card shadow="never">
+            <el-table v-loading="loading" :data="recordCompanyList" border @selection-change="handleSelectionChange">
+                <el-table-column type="selection" width="55" align="center" />
+                <el-table-column label="企业名称" align="center" prop="cpyName" />
+                <el-table-column label="企业logo" align="center" prop="license" width="100">
+                    <template #default="scope">
+                        <template v-if="scope.row.storePhoto && typeof scope.row.storePhoto === 'string'">
+                            <image-preview :src="scope.row.storePhoto" :width="50" :height="50" />
+                        </template>
+                        <template v-else>
+                            <span>暂无图片</span>
+                        </template>
+                    </template>
+                </el-table-column>
+                <el-table-column label="信用代码" align="center" prop="creditCode" />
+                <el-table-column label="合作伙伴" align="center" prop="partnerName" />
+                <el-table-column label="营业执照" align="center" prop="license" width="100">
+                    <template #default="scope">
+                        <template v-if="scope.row.license && scope.row.license.url">
+                            <image-preview :src="scope.row.license.url" :width="50" :height="50" />
+                        </template>
+                    </template>
+                </el-table-column>
+                <el-table-column label="所在行政区" align="center" prop="adcdCode">
+                    <template #default="{ row }">
+                        <AreaView :value="row.adcdCode"></AreaView>
+                    </template>
+                </el-table-column>
+                <el-table-column label="具体地址" align="center" prop="address" />
+                <el-table-column label="联系人姓名" align="center" prop="contactPerson" />
+                <el-table-column label="电话" align="center" prop="tel" />
+                <el-table-column label="入驻时间" align="center" prop="createTime" show-overflow-tooltip width="110">
+                    <template #default="scope">
+                        <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center" width="280" fixed="right" class-name="small-padding fixed-width">
+                    <template #default="{ row }">
+                        <el-button @click="handleUser(row)" type="primary"
+                            ><el-icon><User /></el-icon>维护成员</el-button
+                        >
+                        <el-button @click="$router.push({ path: '/enterprise/cpy-detail', query: { cpyid: row.id } })" type="primary"
+                            ><el-icon><View /></el-icon>查看企业信息</el-button
+                        >
+                    </template>
+                </el-table-column>
+            </el-table>
+
+            <pagination
+                v-show="total > 0"
+                :total="total"
+                v-model:page="queryParams.pageNum"
+                v-model:limit="queryParams.pageSize"
+                @pagination="getList"
+            />
+        </el-card>
+    </div>
+    <Staff :info="formItem" v-model:show="showUser"></Staff>
+</template>
+
+<script setup name="Control" lang="ts">
+import { listRecordCompany } from '@/api/enterprise/recordCompany';
+import { RecordCompanyVO, RecordCompanyQuery, RecordCompanyForm } from '@/api/enterprise/recordCompany/types';
+import { AreaView } from '@/views/components';
+import { Staff } from '@/views/settled';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { cpy_res_status, cpy_type } = toRefs<any>(proxy?.useDict('cpy_res_status', 'cpy_type'));
+const recordCompanyList = ref<RecordCompanyVO[]>([]);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const showUser = ref(false);
+const multiple = ref(true);
+const total = ref(0);
+const queryFormRef = ref<ElFormInstance>();
+const recordCompanyFormRef = ref<ElFormInstance>();
+const formItem = ref<any>(null);
+const initFormData: RecordCompanyForm = {
+    storePhoto: undefined,
+    cpyName: undefined,
+    creditCode: undefined,
+    license: undefined,
+    cpyType: undefined,
+    adcdCode: undefined,
+    address: undefined,
+    contactPerson: undefined,
+    tel: undefined
+};
+const data = reactive<PageData<RecordCompanyForm, RecordCompanyQuery>>({
+    form: { ...initFormData },
+    queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        cpyName: undefined,
+        tel: undefined,
+        creditCode: undefined,
+        status: '1'
+    },
+    rules: {
+        storePhoto: [{ required: true, trigger: 'blur', message: '请上传企业logo' }],
+        cpyName: [{ required: true, trigger: 'blur', message: '请填写企业名称' }],
+        creditCode: [{ required: true, trigger: 'blur', message: '请填写18位统一社会信用代码' }],
+        license: [{ required: true, trigger: 'blur', message: '请上传营业执照' }],
+        cpyType: [{ required: true, trigger: 'blur', message: '请选择结构类型' }],
+        adcdCode: [{ required: true, trigger: 'blur', message: '请选择所在行政区' }],
+        address: [{ required: true, trigger: 'blur', message: '请填写具体地址' }],
+        contactPerson: [{ required: true, trigger: 'blur', message: '请填写企业联系人姓名' }],
+        tel: [{ required: true, trigger: 'blur', message: '请填写企业联系电话' }]
+    }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+// 审批办理
+/** 查询企业备案信息列表 */
+const getList = async () => {
+    loading.value = true;
+    const res = await listRecordCompany(queryParams.value);
+    recordCompanyList.value = res.rows;
+    total.value = res.total;
+    loading.value = false;
+};
+
+/** 表单重置 */
+const reset = () => {
+    form.value = { ...initFormData };
+    recordCompanyFormRef.value?.resetFields();
+};
+// 打开用户信息页面
+const handleUser = (item: any) => {
+    formItem.value = item;
+    showUser.value = true;
+};
+/** 搜索按钮操作 */
+const handleQuery = () => {
+    queryParams.value.pageNum = 1;
+    getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+    queryFormRef.value?.resetFields();
+    handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: RecordCompanyVO[]) => {
+    ids.value = selection.map((item) => item.id);
+    single.value = selection.length != 1;
+    multiple.value = !selection.length;
+};
+
+onMounted(() => {
+    getList();
+});
+</script>

+ 86 - 0
src/views/settled/cpy/index.vue

@@ -0,0 +1,86 @@
+<template>
+    <div class="p-2">
+        <el-card style="width: 100%;margin-bottom: 16px;" v-loading="qyxxLoadding">
+            <el-descriptions title="企业信息" :column="4" border direction="vertical">
+                <template #extra>
+                    <el-button @click="eidtCpy" type="primary" text
+                        ><el-icon><EditPen /></el-icon>编辑</el-button
+                    >
+                </template>
+                <el-descriptions-item label="企业logo">
+                    <template #default>
+                        <HAvatar :src="form.storePhoto" :name="form.cpyName"></HAvatar>
+                    </template>
+                </el-descriptions-item>
+                <el-descriptions-item label="企业名称">{{ form.cpyName }}</el-descriptions-item>
+                <el-descriptions-item label="企业类型">{{ selectDictLabel(cpy_type, form.cpyType) }}</el-descriptions-item>
+                <el-descriptions-item label="统一社会信用代码">{{ form.creditCode }}</el-descriptions-item>
+                <el-descriptions-item label="营业执照" class="d-flex a-c">
+                    <template #default>
+                        <FileLook v-model="form.license"></FileLook>
+                    </template>
+                </el-descriptions-item>
+                <el-descriptions-item label="地址" class="d-flex a-c">
+                    <template #default>
+                        <AreaView :value="form.adcdCode"></AreaView>
+                        <span>{{ form.address }}</span>
+                    </template>
+                </el-descriptions-item>
+                <el-descriptions-item label="企业联系人">{{ form.contactPerson }}</el-descriptions-item>
+                <el-descriptions-item label="企业联系电话">{{ form.tel }}</el-descriptions-item>
+            </el-descriptions>
+        </el-card>
+        <el-card style="width: 100%;margin-bottom: 16px;">
+            <div class="f-14 f-w-b mb15">普通资质</div>
+            <baseAuthInfo :cpyid="(query.cpyid as string)"></baseAuthInfo>
+            <div class="f-14 f-w-b mb15" style="padding-top: 16px;">特殊资质</div>
+            <specialAuthInfo :cpyid="(query.cpyid as string)"></specialAuthInfo>
+        </el-card>
+        <el-card style="width: 100%;margin-bottom: 16px;">
+            <div class="d-flex j-sb mb10">
+                <div class="f-14 f-w-b mb15">授权应用</div>
+                <el-button @click="addApp(authAppRef)" type="primary" text
+                    ><el-icon><Plus /></el-icon>新增应用</el-button
+                >
+            </div>
+            <authApp ref="authAppRef" :cpyid="(query.cpyid as string)"></authApp>
+        </el-card>
+    </div>
+    <!-- 添加或修改企业备案信息对话框 -->
+    <editCpy v-model:show="show1" title="编辑企业信息" :info="formItem" @seccess="changeForm"></editCpy>
+</template>
+<script setup name="Staff" lang="ts">
+import { companyDetail } from '@/api/settled';
+import { FileLook, AreaView } from '@/views/components';
+import { editCpy, baseAuthInfo, specialAuthInfo, authApp } from '@/views/settled';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { cpy_res_status, cpy_type } = toRefs<any>(proxy?.useDict('cpy_res_status', 'cpy_type'));
+const { query } = useRoute();
+const form = ref<any>({});
+const show1 = ref(false);
+const qyxxLoadding = ref(false);
+const authAppRef = ref();
+const formItem = ref<any>(null);
+const getDetail = async () => {
+    qyxxLoadding.value = true;
+    const res = await companyDetail(query.cpyid);
+    qyxxLoadding.value = false;
+    if (!res) return;
+    Object.assign(form.value, res.data);
+};
+const eidtCpy = () => {
+    formItem.value = { ...form.value };
+    show1.value = true;
+};
+const changeForm = (event: any) => {
+    Object.assign(form.value, event);
+};
+const addApp = (authAppRef: any) => {
+  if (!authAppRef) return
+  authAppRef.addApp()
+}
+onMounted(() => {
+    getDetail();
+});
+</script>
+<style lang="scss" scoped></style>

+ 7 - 0
src/views/settled/index.ts

@@ -0,0 +1,7 @@
+export { default as Staff } from './model/staff.vue'; // 企业人员维护
+export { default as editCpy } from './model/editCpy.vue'; // 企业人员维护
+export { default as baseAuthInfo } from './model/baseAuthInfo.vue'; // 企业资质维护
+export { default as CpyAuthDetail } from './model/CpyAuthDetail.vue'; // 企业资质维护
+export { default as specialAuthInfo } from './model/specialAuthInfo.vue'; // 企业资质维护
+export { default as CpyCheckDetail } from './model/CpyCheckDetail.vue'; // 企业资质维护
+export { default as authApp } from './model/authApp.vue'; // 企业资质维护

Some files were not shown because too many files changed in this diff