Bladeren bron

机构编辑页面分块

yuwenjun1997 2 jaren geleden
bovenliggende
commit
db0e626f6a

+ 6 - 4
src/router/index.js

@@ -22,13 +22,14 @@ import normalAduit from './module/normal/audit'
 import normalClub from './module/normal/club'
 import normalClub from './module/normal/club'
 import normalFeedback from './module/normal/feedback'
 import normalFeedback from './module/normal/feedback'
 import normalMaterial from './module/normal/material'
 import normalMaterial from './module/normal/material'
-import docsRoutes from './module/normal/docs'
+import normalDocs from './module/normal/docs'
 import normalPersonal from './module/normal/personal'
 import normalPersonal from './module/normal/personal'
 import normalPersonnel from './module/normal/personnel'
 import normalPersonnel from './module/normal/personnel'
 import normalVip from './module/normal/vip'
 import normalVip from './module/normal/vip'
 import normalUser from './module/normal/user'
 import normalUser from './module/normal/user'
 import normalSettings from './module/normal/settings'
 import normalSettings from './module/normal/settings'
-import activityRoutes from './module/normal/activity'
+import normalActivity from './module/normal/activity'
+import normalPersonalized from './module/normal/personalized'
 
 
 // 需要权限访问的路由列表
 // 需要权限访问的路由列表
 export const asyncRoutes = [
 export const asyncRoutes = [
@@ -42,11 +43,12 @@ export const asyncRoutes = [
   ...normalClub,
   ...normalClub,
   ...normalFeedback,
   ...normalFeedback,
   ...normalMaterial,
   ...normalMaterial,
-  ...docsRoutes,
+  ...normalDocs,
   ...normalPersonal,
   ...normalPersonal,
   ...normalPersonnel,
   ...normalPersonnel,
   ...normalSettings,
   ...normalSettings,
-  ...activityRoutes,
+  ...normalPersonalized,
+  ...normalActivity,
   ...normalUser
   ...normalUser
 ]
 ]
 
 

+ 22 - 0
src/router/module/normal/personalized.js

@@ -0,0 +1,22 @@
+import Layout from '@/layout'
+
+const personalizedRoutes = [
+  {
+    path: '/personalized',
+    component: Layout,
+    redirect: '/personalized/banner',
+    name: 'Personalized',
+    meta: { title: '个性化设置', noCache: true },
+    alwaysShow: true,
+    children: [
+      {
+        path: 'banner',
+        component: () => import('@/views/normal/personalized/banner'),
+        name: 'PersonalBanner',
+        meta: { title: '首页banner', noCache: true }
+      }
+    ]
+  }
+]
+
+export default personalizedRoutes

+ 16 - 0
src/utils/index.js

@@ -430,3 +430,19 @@ export function generateQueryUrl(url, queryObj) {
   }
   }
   return url
   return url
 }
 }
+
+/**
+ * 合并对象属性 将目标对象的属性合并到源对象
+ * @param {*} source
+ * @param {*} target
+ * @returns
+ */
+export function mergeObject(source, target) {
+  // 合并对象
+  for (const key in target) {
+    if (Object.hasOwnProperty.call(source, key)) {
+      source[key] = target[key]
+    }
+  }
+  return source
+}

+ 2 - 2
src/views/admin/settings/menus/components/table-list.vue

@@ -136,7 +136,7 @@ export default {
         parentId: '',
         parentId: '',
         menuType: '', // 1:管理员 2:供应商
         menuType: '', // 1:管理员 2:供应商
         status: '',
         status: '',
-        pageSize: 10,
+        pageSize: 20,
         pageNum: 1
         pageNum: 1
       },
       },
       total: 0,
       total: 0,
@@ -200,7 +200,7 @@ export default {
     // 获取列表
     // 获取列表
     async getList() {
     async getList() {
       this.listQuery.menuType = this.menuType
       this.listQuery.menuType = this.menuType
-      this.listQuery.pageNum = 1
+      // this.listQuery.pageNum = 1
       try {
       try {
         const res = await fetchMenuList(this.listQuery)
         const res = await fetchMenuList(this.listQuery)
         this.list = res.data.list.map((item) => {
         this.list = res.data.list.map((item) => {

+ 148 - 0
src/views/normal/club/components/ClubAssociated.vue

@@ -0,0 +1,148 @@
+<template>
+  <div>
+    <el-form ref="form" label-width="100px" :model="formData" :rules="rules">
+      <el-form-item label="已关联机构:">
+        <el-button size="mini" type="primary" @click="onChooseAssClub">关联机构</el-button>
+      </el-form-item>
+      <el-form-item>
+        <associated-club-list
+          :selection="false"
+          :control="true"
+          :list="filterSelectAssClubList"
+          @filter="onFilterSelectAssClubList"
+        >
+          <template #control="{ row }">
+            <el-button size="mini" type="danger" @click="onAssClubListRemove(row)">删除</el-button>
+          </template>
+        </associated-club-list>
+      </el-form-item>
+    </el-form>
+
+    <!-- 关联机构 -->
+    <el-dialog title="添加关联机构" :visible.sync="assClubListVisible" width="30%" :show-close="false">
+      <associated-club-list
+        v-if="assClubListVisible"
+        :selection="true"
+        :control="false"
+        height="280"
+        :list="assClubList"
+        @filter="onFilterAssClubList"
+        @selected="onAssClubListChange"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" size="mini" @click="onAssClubListCancel">取 消</el-button>
+        <el-button type="primary" size="mini" @click="onAssClubListConfirm">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { AssociatedClubList } from '@/views/components/index'
+import { mapGetters } from 'vuex'
+import { fecthAuthList } from '@/api/auth'
+
+export default {
+  name: 'ClubAssociated',
+  components: {
+    AssociatedClubList
+  },
+  data() {
+    return {
+      formData: {},
+      rules: {},
+      assClubListVisible: false,
+      // 关联机构相关
+      assClubQuery: {
+        pageNum: 1,
+        pageSize: 1000,
+        authParty: ''
+      },
+      assClubList: [], // 关联机构列表
+      selectAssClubList: [], // 当前选中关联机构列表
+      selectAssClubListAll: [], // 全部选中关联机构列表
+      filterSelectAssClubList: [] // 筛选后的关联机构列表
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId'])
+  },
+  methods: {
+    // 初始化表单
+    initForm(data) {
+      // 关联机构列表
+      if (data.releationClubList) {
+        this.selectAssClubListAll = data.releationClubList
+        this.filterSelectAssClubList = this.selectAssClubListAll
+      }
+    },
+    // 验证表单
+    async validateForm() {
+      try {
+        await this.$refs.form.validate()
+        return { selectAssClubListAll: this.selectAssClubListAll }
+      } catch (error) {
+        return Promise.reject(error)
+      }
+    },
+    // 关联机构选择
+    onChooseAssClub() {
+      this.fetchAssClubList()
+      this.assClubListVisible = true
+    },
+    // 获取关联机构列表
+    async fetchAssClubList() {
+      try {
+        const excludeId = this.selectAssClubListAll.map((item) => item.authId)
+        if (this.authId) {
+          excludeId.push(parseInt(this.authId))
+        }
+        const res = await fecthAuthList(this.assClubQuery)
+        this.assClubList = res.data.list.filter((item) => !excludeId.includes(item.authId))
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 关联机构列表筛选
+    onFilterAssClubList(query) {
+      this.assClubQuery.authParty = query.authParty
+      this.fetchAssClubList()
+    },
+    // 关联机构列表选中
+    onAssClubListChange(value) {
+      this.selectAssClubList = value
+    },
+    // 关联机构选中列表确认
+    onAssClubListConfirm() {
+      this.selectAssClubListAll = [...this.selectAssClubListAll, ...this.selectAssClubList]
+      this.filterSelectAssClubList = this.selectAssClubListAll
+      this.assClubQuery.authParty = ''
+      this.assClubList = []
+      this.assClubListVisible = false
+    },
+    // 关联机构选中列表取消
+    onAssClubListCancel() {
+      this.selectAssClubList = []
+      this.filterSelectAssClubList = this.selectAssClubListAll
+      this.assClubQuery.authParty = ''
+      this.assClubList = []
+      this.assClubListVisible = false
+    },
+    // 已关联机构列表筛选
+    onFilterSelectAssClubList(query) {
+      if (query.authParty) {
+        this.filterSelectAssClubList = this.selectAssClubListAll.filter((item) =>
+          new RegExp(query.authParty, 'ig').test(item.authParty)
+        )
+      } else {
+        this.filterSelectAssClubList = this.selectAssClubListAll
+      }
+    },
+    // 已关联机构列表删除
+    onAssClubListRemove(row) {
+      this.selectAssClubListAll = this.selectAssClubListAll.filter((item) => item.authId !== row.authId)
+      this.filterSelectAssClubList = this.selectAssClubListAll
+    }
+  }
+}
+</script>

+ 195 - 0
src/views/normal/club/components/ClubAuthorizeBrand.vue

@@ -0,0 +1,195 @@
+<template>
+  <el-form ref="form" label-width="100px" :model="formData" :rules="rules">
+    <el-form-item label="授权牌:">
+      <el-radio-group v-model="formData.authImageType" size="mini">
+        <el-radio :label="1" border>模板库生成</el-radio>
+        <el-radio :label="2" border>自定义上传</el-radio>
+      </el-radio-group>
+      <div style="margin-top: 12px">
+        <template v-if="formData.authImageType === 2">
+          <upload-image
+            tip="建议尺寸:542px * 546px"
+            :image-list="authImageList"
+            :before-upload="beforeAuthImageUpload"
+            @success="uploadAuthImageSuccess"
+            @remove="handleAuthImageRemove"
+          />
+          <el-input v-show="false" v-model="formData.authImage" />
+        </template>
+        <template v-else>
+          <template v-if="authTempFlag">
+            <preview-image v-if="formData.authImage" width="148px" height="148px" :src="formData.authImage" />
+          </template>
+          <template v-else>无</template>
+        </template>
+      </div>
+    </el-form-item>
+
+    <el-form-item v-if="authTempFlag && formData.authImageType === 1" label="授权牌logo:">
+      <div class="form-label-tip">授权牌logo(提示:授权牌logo与机构名称组合)</div>
+      <div style="margin-top: 8px">
+        <upload-image
+          :tip="authImageLogoUploadTip"
+          :image-list="authImageLogoList"
+          :before-upload="beforeAuthImageLogoUpload"
+          @success="uploadAuthImageLogoSuccess"
+          @remove="handleAuthImageLogoRemove"
+        />
+        <el-input v-show="false" v-model="formData.authImageLogo" />
+      </div>
+    </el-form-item>
+    <el-form-item label="认证编号:" prop="authCode">
+      <el-input v-model="formData.authCode" placeholder="请输认证编号" clearable />
+    </el-form-item>
+
+    <el-form-item label="认证日期:" prop="authDate">
+      <el-date-picker v-model="formData.authDate" type="date" placeholder="选择日期" style="width: 100%" />
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import UploadImage from '@/components/UploadImage'
+import { mapGetters } from 'vuex'
+import { authTempUsed } from '@/api/system'
+
+export default {
+  name: 'ClubAuthorizeBrand',
+  components: {
+    UploadImage
+  },
+  data() {
+    return {
+      formData: {
+        // 新增授权牌字段
+        authCode: '',
+        authDate: '',
+        authImageType: 1,
+        authImageLogo: '',
+        authImage: ''
+      },
+      rules: {
+        authImageLogo: [{ required: true, message: '请上传授权牌logo', trigger: 'change' }]
+      },
+      // 授权牌照图片列表
+      authImageList: [],
+      // 授权牌logo列表
+      authImageLogoList: [],
+      // 验证
+      validatorFields: {
+        authImageLogoWidth: 100,
+        authImageLogoHeight: 100
+      },
+      // 授权牌模板标识
+      authTempFlag: false
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo']),
+    // 授权牌logo上传提示
+    authImageLogoUploadTip() {
+      return `限制尺寸:${this.validatorFields.authImageLogoWidth}px *${this.validatorFields.authImageLogoHeight}px`
+    }
+  },
+  created() {
+    this.fetchAuthTempUsed()
+  },
+  methods: {
+    // 初始化表单
+    initForm(data) {
+      // 授权牌相关字段
+      this.formData.authCode = data.authCode
+      this.formData.authDate = data.authDate
+      this.formData.authImageType = data.authImageType
+
+      this.formData.authImageLogo = data.authImageLogo
+      if (data.authImageLogo) {
+        this.authImageLogoList = [{ name: '授权牌logo', url: data.authImageLogo }]
+      }
+
+      this.formData.authImage = data.authImage
+      if (data.authImage) {
+        this.authImageList = [{ name: '自定义授权牌', url: data.authImage }]
+      }
+    },
+
+    // 验证表单
+    async validateForm() {
+      try {
+        await this.$refs.form.validate()
+        return this.formData
+      } catch (error) {
+        return Promise.reject(error)
+      }
+    },
+
+    // 获取当前机构可用授权牌模板
+    async fetchAuthTempUsed() {
+      try {
+        const res = await authTempUsed({
+          authUserId: this.authUserId,
+          authFlag: 1,
+          status: 1
+        })
+        if (res.data) {
+          const [width, height] = res.data.logoSize.split(',')
+          this.validatorFields.authImageLogoWidth = width
+          this.validatorFields.authImageLogoHeight = height
+          this.authTempFlag = true
+        } else {
+          this.authTempFlag = false
+        }
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 授权牌照上传
+    beforeAuthImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 5
+      if (!flag) {
+        this.$message.error('上传授权牌图片大小不能超过 5MB!')
+      }
+      return flag
+    },
+    uploadAuthImageSuccess({ response, file, fileList }) {
+      this.authImageList = fileList
+      this.formData.authImage = response.data
+    },
+    handleAuthImageRemove({ file, fileList }) {
+      this.authImageList = fileList
+      this.formData.authImage = ''
+    },
+
+    // 授权牌logo上传
+    beforeAuthImageLogoUpload(file) {
+      return new Promise((resolve, reject) => {
+        if (file.size > 5 * 1024 * 1024) {
+          this.$message.error('授权牌logo图片大小不能超过 5MB!')
+          reject('图片大小超出最大限制')
+        }
+        const image = new Image()
+        image.src = URL.createObjectURL(file)
+        image.onload = (e) => {
+          const { naturalWidth, naturalHeight } = e.path ? e.path[0] : e.target
+          const { authImageLogoWidth: width, authImageLogoHeight: height } = this.validatorFields
+          if (naturalWidth > width || naturalHeight > height) {
+            this.$message.error('图片尺寸校验未通过')
+            reject('图片尺寸校验未通过')
+          } else {
+            resolve('图片尺寸校验通过')
+          }
+        }
+      })
+    },
+    uploadAuthImageLogoSuccess({ response, file, fileList }) {
+      this.authImageLogoList = fileList
+      this.formData.authImageLogo = response.data
+    },
+    handleAuthImageLogoRemove({ file, fileList }) {
+      this.authImageLogoList = fileList
+      this.formData.authImageLogo = ''
+    }
+  }
+}
+</script>

+ 422 - 0
src/views/normal/club/components/ClubBasicsInfo.vue

@@ -0,0 +1,422 @@
+<template>
+  <div>
+    <el-form ref="form" label-width="140px" :model="formData" :rules="rules">
+      <el-form-item label="机构名称:" prop="authParty">
+        <el-input v-model="formData.authParty" placeholder="请输入机构名称" clearable />
+      </el-form-item>
+      <el-form-item label="所在地区:" prop="address">
+        <el-cascader
+          ref="cascader"
+          v-model="formData.address"
+          :class="{ display: cascaderDisplay }"
+          clearable
+          :props="cascaderProps"
+          style="width: 100%"
+          :placeholder="cascaderPlaceholder"
+          @change="handleChange"
+        />
+      </el-form-item>
+      <el-form-item label="详细地址:" prop="fullAddress">
+        <el-input v-model="formData.fullAddress" placeholder="请输入详细地址" clearable @blur="initGeocoder" />
+      </el-form-item>
+      <el-form-item label="经纬度:" prop="point">
+        <el-input
+          v-model="formData.point"
+          placeholder="请输入经纬度 (格式:纬度,经度,可通过右侧地图小按钮获取)"
+          clearable
+        >
+          <el-button slot="append" icon="el-icon-map-location" @click="initMap" />
+        </el-input>
+      </el-form-item>
+      <el-form-item label="联系电话:">
+        <el-input v-model="formData.mobile" placeholder="请输入联系方式" clearable />
+      </el-form-item>
+
+      <el-form-item label="运营联系人:">
+        <el-input v-model="formData.linkMan" placeholder="请输入运营联系人" clearable />
+      </el-form-item>
+
+      <el-form-item label="运营联系人手机号:">
+        <el-input
+          v-model="formData.linkMobile"
+          placeholder="请输入运营联系人手机号"
+          clearable
+          maxlength="11"
+          show-word-limit
+          @input="onMobileInput"
+        />
+      </el-form-item>
+      <!-- <el-form-item label="手机号:" prop="userMobile">
+        <el-input v-model="formData.userMobile" placeholder="请输入手机号" clearable maxlength="11" show-word-limit />
+      </el-form-item> -->
+      <el-form-item label="机构logo:" prop="logo">
+        <el-input v-show="false" v-model="formData.logo" />
+        <upload-image
+          tip="建议尺寸:242px * 242px"
+          :image-list="logoList"
+          :before-upload="beforeLogoUpload"
+          @success="uploadLogoSuccess"
+          @remove="handleLogoRemove"
+        />
+      </el-form-item>
+      <el-form-item label="门头照:" prop="banner">
+        <div class="form-label-tip">至少上传一张机构门店图,最多上传6张)</div>
+        <el-input v-show="false" v-model="formData.banner" />
+        <upload-image
+          tip="至少上传一张,最多6张;建议尺寸:542px * 542px"
+          :image-list="bannerList"
+          :before-upload="beforeBannerUpload"
+          :limit="6"
+          @success="uploadBannerSuccess"
+          @remove="handleBannerRemove"
+        />
+      </el-form-item>
+
+      <!-- **************** 新方法配置授权牌 End ******************* -->
+
+      <el-form-item label="机构类型:">
+        <el-radio-group v-model="formData.firstClubType">
+          <el-radio :label="1">医美</el-radio>
+          <el-radio :label="2">生美</el-radio>
+          <el-radio :label="3">项目公司</el-radio>
+          <el-radio :label="4">个人</el-radio>
+          <el-radio :label="5">其他</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item v-if="formData.firstClubType === 1" label="医美类型:">
+        <el-radio-group v-model="formData.secondClubType">
+          <el-radio :label="1">诊所</el-radio>
+          <el-radio :label="2">门诊</el-radio>
+          <el-radio :label="3">医院</el-radio>
+          <el-radio :label="4">其他</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item v-if="formData.firstClubType === 2" label="生美类型:">
+        <el-radio-group v-model="formData.secondClubType">
+          <el-radio :label="5">美容院</el-radio>
+          <el-radio :label="6">养生馆</el-radio>
+          <el-radio :label="7">其他</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item v-if="formData.firstClubType === 1" label="医疗许可证:" prop="medicalLicenseImage">
+        <el-input v-show="false" v-model="formData.medicalLicenseImage" />
+        <upload-image
+          tip="请上传医疗许可证;建议尺寸:542px * 542px"
+          :limit="1"
+          :image-list="licenseImageList"
+          :before-upload="beforeLicenseImageUpload"
+          @success="uploadLicenseImageSuccess"
+          @remove="handleLicenseImageRemove"
+        />
+      </el-form-item>
+
+      <el-form-item label="员工人数:" prop="empNum">
+        <el-input v-model.number="formData.empNum" placeholder="请输入员工人数" clearable />
+      </el-form-item>
+    </el-form>
+
+    <!-- 地图坐标拾取 -->
+    <el-dialog
+      class="map-dialog"
+      title="坐标拾取(请拖动标记点选取准确位置)"
+      :visible.sync="dialogMapVisible"
+      width="80%"
+    >
+      <a-map ref="aMap" :lnglat="lnglat" :address="locationAddress" @position="onPosition" />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" size="mini" @click="dialogMapVisible = false">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import SimpleAMap from '@/components/SimpleAMap'
+import UploadImage from '@/components/UploadImage'
+import { mapGetters } from 'vuex'
+import { getAddress } from '@/api/common'
+import { isMobile, isNumber } from '@/utils/validate'
+import { initGeocoder } from '@/components/SimpleAMap/common/utils'
+
+export default {
+  name: 'ClubBasicsInfo',
+  components: {
+    [SimpleAMap.name]: SimpleAMap,
+    UploadImage
+  },
+  data() {
+    var validateMobile = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('联系方式不能为空'))
+      } else {
+        if (isNumber(value)) {
+          callback()
+        } else {
+          callback(new Error('联系方式格式不正确'))
+        }
+      }
+    }
+
+    var validatePhoneNumber = (rule, value, callback) => {
+      if (!value || isMobile(value)) {
+        callback()
+      } else {
+        callback(new Error('手机号格式不正确'))
+      }
+    }
+
+    return {
+      dialogMapVisible: false,
+      point: {},
+      value: [],
+      area: '',
+      formData: {
+        authParty: '',
+        address: [],
+        fullAddress: '',
+        point: '',
+        mobile: '',
+        userMobile: '',
+        logo: '',
+        banner: '',
+        empNum: '',
+        firstClubType: 1,
+        secondClubType: 1,
+        medicalLicenseImage: '',
+        // 新增运营人字段
+        linkMan: '',
+        linkMobile: ''
+      },
+      rules: {
+        authParty: [{ required: true, message: '机构名称不能为空', trigger: ['blur', 'change'] }],
+        address: [{ required: true, message: '地址不能为空', trigger: 'change', type: 'array' }],
+        fullAddress: [{ required: true, message: '详细不能为空', trigger: ['blur', 'change'] }],
+        mobile: [{ required: true, validator: validateMobile, trigger: ['blur', 'change'] }],
+        logo: [{ required: true, message: '请上传机构logo', trigger: 'change' }],
+        banner: [{ required: true, message: '请至少上传一张banner图片', trigger: 'change' }],
+        medicalLicenseImage: [{ required: true, message: '请上传医疗许可证', trigger: 'change' }],
+        empNum: [{ required: true, message: '员工人数不能为空', trigger: 'change' }],
+        userMobile: [{ validator: validatePhoneNumber, trigger: 'change' }]
+      },
+      // logo图片列表
+      logoList: [],
+      // banner图片列表
+      bannerList: [],
+      // 级联选择的地址
+      address: '',
+      // 医疗许可证图片
+      licenseImageList: [],
+      // 验证
+      validatorFields: {
+        authImageLogoWidth: 100,
+        authImageLogoHeight: 100
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId']),
+    // 级联选择器
+    cascaderProps() {
+      return {
+        lazy: true,
+        lazyLoad: async(node, resolve) => {
+          const { level, value = 0 } = node
+          const result = await getAddress({ parentId: value, type: level })
+          const nodes = result.data.map((item) => ({ value: item.id, label: item.name, leaf: level >= 2 }))
+          resolve(nodes)
+        }
+      }
+    },
+    cascaderDisplay() {
+      return this.formData.address.length > 0
+    },
+    cascaderPlaceholder() {
+      return this.cascaderDisplay ? this.area : '请选择所在区域'
+    },
+    // 定位使用的地址
+    locationAddress() {
+      // 广东省/深圳市/福田区景峰大厦
+      return this.address + this.formData.fullAddress
+    },
+    // 位置坐标
+    lnglat() {
+      return this.formData.point ? this.formData.point.split(',') : null
+    }
+  },
+  methods: {
+    // 初始化表单
+    initForm(data) {
+      this.formData.authParty = data.authParty
+      this.formData.fullAddress = data.address
+      this.formData.point = data.lngAndLat
+      this.formData.mobile = data.mobile
+      this.formData.logo = data.logo || ''
+      this.formData.banner = data.bannerList.length || ''
+      this.formData.relationId = data.relationId
+      this.formData.relationName = data.relationName
+      this.formData.customFlag = data.customFlag
+      this.formData.remarks = data.remarks
+      if (data.logo) {
+        this.logoList = [{ name: '机构logo', url: data.logo }]
+      }
+      if (data.bannerList.length > 0) {
+        this.bannerList = data.bannerList.map((item, index) => ({ name: `门头照${index}`, url: item }))
+      }
+      this.formData.address = [data.provinceId, data.cityId, data.townId]
+      this.area = data.area
+      this.address = data.area
+      this.formData.empNum = data.empNum
+      // 机构类型
+      this.formData.firstClubType = data.firstClubType
+      this.formData.secondClubType = data.secondClubType
+      // 医疗许可证
+      this.formData.medicalLicenseImage = data.medicalLicenseImage
+      if (data.medicalLicenseImage) {
+        this.licenseImageList = [{ name: '医疗许可证', url: data.medicalLicenseImage }]
+      }
+      // 用户手机号
+      this.formData.userMobile = data.userMobile
+      // 运营人相关
+      this.formData.linkMan = data.linkMan
+      this.formData.linkMobile = data.linkMobile
+      // 如果经纬度为空
+      if (!data.lngAndLat && this.locationAddress) {
+        this.initGeocoder()
+      }
+    },
+    // 验证表单
+    async validateForm() {
+      try {
+        // 如果经纬度为空
+        if (!this.formData.point && this.locationAddress) {
+          await this.initGeocoder()
+        }
+        await this.$refs.form.validate()
+        return { bannerList: this.bannerList, ...this.formData }
+      } catch (error) {
+        return Promise.reject(error)
+      }
+    },
+    // 根据地址信息定位
+    async initGeocoder() {
+      try {
+        const geocoder = await initGeocoder()
+        geocoder.getLocation(this.locationAddress, (status, result) => {
+          if (status === 'complete' && result.info === 'OK') {
+            const position = result.geocodes[0].location
+            this.onPosition(position)
+          } else {
+            console.log(result)
+          }
+        })
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 地图定位
+    initMap() {
+      this.dialogMapVisible = true
+      this.$nextTick(() => {
+        this.$refs.aMap.init()
+      })
+    },
+
+    // 获取位置坐标
+    onPosition(lnglat) {
+      this.formData.point = `${lnglat.lng},${lnglat.lat}`
+    },
+
+    // 获取地址
+    initAddress() {
+      return getAddress({
+        parentId: 19,
+        type: 1
+      })
+    },
+
+    // 地图标记变化
+    markerChange(point) {
+      this.formData.point = `${point.lng},${point.lat}`
+    },
+
+    handleChange(e) {
+      const node = this.$refs.cascader.getCheckedNodes()
+      if (node.length <= 0) return
+      this.address = node[0].pathLabels.join()
+      this.initGeocoder()
+    },
+
+    // logo上传
+    uploadLogoSuccess({ response, file, fileList }) {
+      this.logoList = fileList
+      this.formData.logo = fileList[0].response.data
+    },
+    handleLogoRemove({ file, fileList }) {
+      this.logoList = fileList
+      this.formData.logo = ''
+    },
+    beforeLogoUpload(file) {
+      const flag = file.size / 1024 < 500
+      if (!flag) {
+        this.$message.error('上传logo图片大小不能超过 500kb!')
+      }
+      return flag
+    },
+
+    // banner上传
+    uploadBannerSuccess({ response, file, fileList }) {
+      this.bannerList = fileList
+      console.log(this.bannerList)
+      this.formData.banner = fileList.length > 0 ? fileList.length : ''
+    },
+    handleBannerRemove({ file, fileList }) {
+      this.bannerList = fileList
+      this.formData.banner = fileList.length > 0 ? fileList.length : ''
+    },
+    beforeBannerUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传banner图片大小不能超过 1MB!')
+      }
+      return flag
+    },
+
+    // 医疗许可证图片上传
+    uploadLicenseImageSuccess({ response, file, fileList }) {
+      this.licenseImageList = fileList
+      console.log(this.licenseImageList)
+      this.formData.medicalLicenseImage = response.data
+    },
+    handleLicenseImageRemove({ file, fileList }) {
+      this.licenseImageList = fileList
+      this.formData.medicalLicenseImage = ''
+    },
+    beforeLicenseImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('医疗许可证图片大小不能超过 1MB!')
+      }
+      return flag
+    },
+    // 输入手机号时
+    onMobileInput() {
+      this.formData.mobile = this.formData.mobile.replace(/[^\w\.\/]/gi, '')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+#allmap {
+  width: 100%;
+  height: 600px;
+}
+
+.attributes {
+  padding-top: 16px;
+}
+</style>

+ 72 - 0
src/views/normal/club/components/ClubSpecialInfo.vue

@@ -0,0 +1,72 @@
+<template>
+  <el-form ref="form" label-width="110px" :model="formData" :rules="rules">
+    <el-form-item prop="remarks">
+      <template #label>店铺备注:</template>
+      <el-checkbox v-model="formData.customFlag" :true-label="1" :false-label="0" size="medium" @change="handleRemarksChange" />
+      <el-input
+        v-model="formData.remarks"
+        placeholder="店铺备注"
+        clearable
+        :disabled="formData.customFlag === 0"
+        @change="handleRemarksChange"
+      />
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+
+export default {
+  name: 'ClubSpecialInfo',
+  data() {
+    return {
+      formData: {
+        customFlag: 0,
+        remarks: ''
+      },
+      rules: {
+        remarks: [{ required: true, message: '请输入店铺备注', trigger: 'blur' }]
+      }
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo'])
+  },
+  created() {},
+  methods: {
+    // 初始化表单
+    initForm(data) {
+      this.formData.customFlag = data.customFlag
+      this.formData.remarks = data.remarks
+    },
+    validateField(props) {
+      return new Promise((resolve, reject) => {
+        this.$refs.form.validateField(props, (errorMsg) => (errorMsg ? reject(errorMsg) : resolve()))
+      })
+    },
+    // 验证表单
+    async validateForm() {
+      try {
+        const props = this.formData.customFlag === 1 ? ['remarks'] : []
+        if (props.length > 0) {
+          await this.validateField(props)
+        }
+        return this.formData
+      } catch (error) {
+        return Promise.reject(error)
+      }
+    },
+    handleRemarksChange() {
+      this.$refs.form.clearValidate()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-checkbox {
+  position: absolute;
+  left: -110px;
+}
+</style>

+ 4 - 0
src/views/normal/club/components/index.js

@@ -0,0 +1,4 @@
+export { default as ClubBasicsInfo } from './ClubBasicsInfo'
+export { default as ClubAssociated } from './ClubAssociated'
+export { default as ClubAuthorizeBrand } from './ClubAuthorizeBrand'
+export { default as ClubSpecialInfo } from './ClubSpecialInfo'

+ 827 - 0
src/views/normal/club/edit copy.vue

@@ -0,0 +1,827 @@
+<template>
+  <div class="club-edit page-form-container">
+    <el-form ref="submitForm" label-width="140px" :model="formData" :rules="rules">
+      <el-form-item label="机构名称:" prop="authParty">
+        <el-input v-model="formData.authParty" placeholder="请输入机构名称" clearable />
+      </el-form-item>
+      <el-form-item label="所在地区:" prop="address">
+        <el-cascader
+          ref="cascader"
+          v-model="formData.address"
+          :class="{ display: cascaderDisplay }"
+          clearable
+          :props="cascaderProps"
+          style="width: 100%"
+          :placeholder="cascaderPlaceholder"
+          @change="handleChange"
+        />
+      </el-form-item>
+      <el-form-item label="详细地址:" prop="fullAddress">
+        <el-input v-model="formData.fullAddress" placeholder="请输入详细地址" clearable @blur="initGeocoder" />
+      </el-form-item>
+      <el-form-item label="经纬度:" prop="point">
+        <el-input
+          v-model="formData.point"
+          placeholder="请输入经纬度 (格式:纬度,经度,可通过右侧地图小按钮获取)"
+          clearable
+        >
+          <el-button slot="append" icon="el-icon-map-location" @click="initMap" />
+        </el-input>
+      </el-form-item>
+      <el-form-item label="联系电话:">
+        <el-input v-model="formData.mobile" placeholder="请输入联系方式" clearable />
+      </el-form-item>
+
+      <el-form-item label="运营联系人:">
+        <el-input v-model="formData.linkMan" placeholder="请输入运营联系人" clearable />
+      </el-form-item>
+
+      <el-form-item label="运营联系人手机号:">
+        <el-input
+          v-model="formData.linkMobile"
+          placeholder="请输入运营联系人手机号"
+          clearable
+          maxlength="11"
+          show-word-limit
+          @input="onMobileInput"
+        />
+      </el-form-item>
+
+      <el-form-item label="认证编号:" prop="authCode">
+        <el-input v-model="formData.authCode" placeholder="请输认证编号" clearable />
+      </el-form-item>
+
+      <el-form-item label="认证日期:" prop="authDate">
+        <el-date-picker v-model="formData.authDate" type="date" placeholder="选择日期" style="width: 100%" />
+      </el-form-item>
+      <!-- <el-form-item label="手机号:" prop="userMobile">
+        <el-input v-model="formData.userMobile" placeholder="请输入手机号" clearable maxlength="11" show-word-limit />
+      </el-form-item> -->
+      <el-form-item label="机构logo:" prop="logo">
+        <el-input v-show="false" v-model="formData.logo" />
+        <upload-image
+          tip="建议尺寸:242px * 242px"
+          :image-list="logoList"
+          :before-upload="beforeLogoUpload"
+          @success="uploadLogoSuccess"
+          @remove="handleLogoRemove"
+        />
+      </el-form-item>
+      <el-form-item label="门头照:" prop="banner">
+        <div class="form-label-tip">至少上传一张机构门店图,最多上传6张)</div>
+        <el-input v-show="false" v-model="formData.banner" />
+        <upload-image
+          tip="至少上传一张,最多6张;建议尺寸:542px * 542px"
+          :image-list="bannerList"
+          :before-upload="beforeBannerUpload"
+          :limit="6"
+          @success="uploadBannerSuccess"
+          @remove="handleBannerRemove"
+        />
+      </el-form-item>
+
+      <!-- **************** 新方法配置授权牌 START ******************* -->
+      <el-form-item label="授权牌:">
+        <el-radio-group v-model="formData.authImageType" size="mini">
+          <el-radio :label="1" border>模板库生成</el-radio>
+          <el-radio :label="2" border>自定义上传</el-radio>
+        </el-radio-group>
+        <div style="margin-top: 12px">
+          <template v-if="formData.authImageType === 2">
+            <upload-image
+              tip="建议尺寸:542px * 546px"
+              :image-list="authImageList"
+              :before-upload="beforeAuthImageUpload"
+              @success="uploadAuthImageSuccess"
+              @remove="handleAuthImageRemove"
+            />
+            <el-input v-show="false" v-model="formData.authImage" />
+          </template>
+          <template v-else>
+            <template v-if="authTempFlag">
+              <preview-image v-if="formData.authImage" width="148px" height="148px" :src="formData.authImage" />
+            </template>
+            <template v-else>无</template>
+          </template>
+        </div>
+      </el-form-item>
+
+      <el-form-item v-if="authTempFlag && formData.authImageType === 1" label="授权牌logo:">
+        <div class="form-label-tip">授权牌logo(提示:授权牌logo与机构名称组合)</div>
+        <div style="margin-top: 8px">
+          <upload-image
+            :tip="authImageLogoUploadTip"
+            :image-list="authImageLogoList"
+            :before-upload="beforeAuthImageLogoUpload"
+            @success="uploadAuthImageLogoSuccess"
+            @remove="handleAuthImageLogoRemove"
+          />
+          <el-input v-show="false" v-model="formData.authImageLogo" />
+        </div>
+      </el-form-item>
+
+      <!-- **************** 新方法配置授权牌 End ******************* -->
+
+      <el-form-item label="机构类型:">
+        <el-radio-group v-model="formData.firstClubType">
+          <el-radio :label="1">医美</el-radio>
+          <el-radio :label="2">生美</el-radio>
+          <el-radio :label="3">项目公司</el-radio>
+          <el-radio :label="4">个人</el-radio>
+          <el-radio :label="5">其他</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item v-if="formData.firstClubType === 1" label="医美类型:">
+        <el-radio-group v-model="formData.secondClubType">
+          <el-radio :label="1">诊所</el-radio>
+          <el-radio :label="2">门诊</el-radio>
+          <el-radio :label="3">医院</el-radio>
+          <el-radio :label="4">其他</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item v-if="formData.firstClubType === 2" label="生美类型:">
+        <el-radio-group v-model="formData.secondClubType">
+          <el-radio :label="5">美容院</el-radio>
+          <el-radio :label="6">养生馆</el-radio>
+          <el-radio :label="7">其他</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item v-if="formData.firstClubType === 1" label="医疗许可证:" prop="medicalLicenseImage">
+        <el-input v-show="false" v-model="formData.medicalLicenseImage" />
+        <upload-image
+          tip="请上传医疗许可证;建议尺寸:542px * 542px"
+          :limit="1"
+          :image-list="licenseImageList"
+          :before-upload="beforeLicenseImageUpload"
+          @success="uploadLicenseImageSuccess"
+          @remove="handleLicenseImageRemove"
+        />
+      </el-form-item>
+
+      <el-form-item label="员工人数:" prop="empNum">
+        <el-input v-model.number="formData.empNum" placeholder="请输入员工人数" clearable />
+      </el-form-item>
+
+      <el-form-item label="自定义属性:">
+        <el-radio-group v-model="formData.customFlag" size="mini">
+          <el-radio :label="0" border>否</el-radio>
+          <el-radio :label="1" border>是</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <template v-if="formData.customFlag === 1">
+        <el-form-item label="店铺备注:" prop="remarks">
+          <el-input v-model="formData.remarks" placeholder="店铺备注" clearable />
+        </el-form-item>
+      </template>
+
+      <el-form-item label="已关联机构:">
+        <el-button size="mini" type="primary" @click="onChooseAssClub">关联机构</el-button>
+      </el-form-item>
+      <el-form-item>
+        <associated-club-list
+          :selection="false"
+          :control="true"
+          :list="filterSelectAssClubList"
+          @filter="onFilterSelectAssClubList"
+        >
+          <template #control="{ row }">
+            <el-button size="mini" type="danger" @click="onAssClubListRemove(row)">删除</el-button>
+          </template>
+        </associated-club-list>
+      </el-form-item>
+    </el-form>
+
+    <!-- 表单提交 返回 -->
+    <div class="control-box">
+      <el-button type="primary" @click="submit">保存</el-button>
+      <el-button type="warning" @click="navigateBack">返回</el-button>
+    </div>
+
+    <!-- 地图坐标拾取 -->
+    <el-dialog
+      class="map-dialog"
+      title="坐标拾取(请拖动标记点选取准确位置)"
+      :visible.sync="dialogMapVisible"
+      width="80%"
+    >
+      <a-map ref="aMap" :lnglat="lnglat" :address="locationAddress" @position="onPosition" />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" size="mini" @click="dialogMapVisible = false">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 关联机构 -->
+    <el-dialog title="添加关联机构" :visible.sync="assClubListVisible" width="30%" :show-close="false">
+      <associated-club-list
+        v-if="assClubListVisible"
+        :selection="true"
+        :control="false"
+        height="280"
+        :list="assClubList"
+        @filter="onFilterAssClubList"
+        @selected="onAssClubListChange"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" size="mini" @click="onAssClubListCancel">取 消</el-button>
+        <el-button type="primary" size="mini" @click="onAssClubListConfirm">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import SimpleAMap from '@/components/SimpleAMap'
+import UploadImage from '@/components/UploadImage'
+import { AssociatedClubList } from '@/views/components/index'
+import { mapGetters } from 'vuex'
+import { saveBrandAuth, getAuthFormData, fecthAuthList } from '@/api/auth'
+import { getAddress } from '@/api/common'
+import { isMobile, isNumber } from '@/utils/validate'
+import { formatDate } from '@/utils'
+import { authTempUsed } from '@/api/system'
+import { initGeocoder } from '@/components/SimpleAMap/common/utils'
+
+export default {
+  components: {
+    [SimpleAMap.name]: SimpleAMap,
+    UploadImage,
+    AssociatedClubList
+  },
+  data() {
+    // var validatePoint = (rule, value, callback) => {
+    //   if (value === '') {
+    //     callback(new Error('经纬度坐标不能为空'))
+    //   } else {
+    //     if (isPoint(value)) {
+    //       callback()
+    //     } else {
+    //       callback(new Error('经纬度坐标格式不正确,(例如:114.095294,22.536004)'))
+    //     }
+    //   }
+    // }
+
+    var validateMobile = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('联系方式不能为空'))
+      } else {
+        if (isNumber(value)) {
+          callback()
+        } else {
+          callback(new Error('联系方式格式不正确'))
+        }
+      }
+    }
+
+    var validatePhoneNumber = (rule, value, callback) => {
+      if (!value || isMobile(value)) {
+        callback()
+      } else {
+        callback(new Error('手机号格式不正确'))
+      }
+    }
+
+    return {
+      editType: 'add',
+      dialogMapVisible: false,
+      point: {},
+      value: [],
+      options: [],
+
+      assClubListVisible: false,
+
+      authId: '',
+      disabled: false,
+      area: '',
+      formData: {
+        authParty: '',
+        address: [],
+        fullAddress: '',
+        point: '',
+        mobile: '',
+        userMobile: '',
+        logo: '',
+        banner: '',
+        customFlag: 0,
+        remarks: '',
+        empNum: '',
+        firstClubType: 1,
+        secondClubType: 1,
+        medicalLicenseImage: '',
+        // 新增授权牌字段
+        authCode: '',
+        authDate: '',
+        authImageType: 1,
+        authImageLogo: '',
+        authImage: '',
+        // 新增运营人字段
+        linkMan: '',
+        linkMobile: '',
+        // 机构关联
+        relationId: '',
+        relationName: ''
+      },
+      rules: {
+        authParty: [{ required: true, message: '机构名称不能为空', trigger: ['blur', 'change'] }],
+        address: [{ required: true, message: '地址不能为空', trigger: 'change', type: 'array' }],
+        fullAddress: [{ required: true, message: '详细不能为空', trigger: ['blur', 'change'] }],
+        // point: [{ required: true, validator: validatePoint, trigger: ['blur', 'change'] }],
+        mobile: [{ required: true, validator: validateMobile, trigger: ['blur', 'change'] }],
+        logo: [{ required: true, message: '请上传机构logo', trigger: 'change' }],
+        banner: [{ required: true, message: '请至少上传一张banner图片', trigger: 'change' }],
+        remarks: [{ required: true, message: '店铺备注不能为空', trigger: 'blur' }],
+        medicalLicenseImage: [{ required: true, message: '请上传医疗许可证', trigger: 'change' }],
+        empNum: [{ required: true, message: '员工人数不能为空', trigger: 'change' }],
+        userMobile: [{ validator: validatePhoneNumber, trigger: 'change' }],
+        authImageLogo: [{ required: true, message: '请上传授权牌logo', trigger: 'change' }]
+      },
+      // logo图片列表
+      logoList: [],
+      // banner图片列表
+      bannerList: [],
+      // 级联选择的地址
+      address: '',
+      // 医疗许可证图片
+      licenseImageList: [],
+      // 授权牌照图片列表
+      authImageList: [],
+      // 授权牌logo列表
+      authImageLogoList: [],
+      // 验证
+      validatorFields: {
+        authImageLogoWidth: 100,
+        authImageLogoHeight: 100
+      },
+      // 授权牌模板标识
+      authTempFlag: false,
+      // 关联机构相关
+      assClubQuery: {
+        pageNum: 1,
+        pageSize: 1000,
+        authParty: ''
+      },
+      assClubList: [], // 关联机构列表
+      selectAssClubList: [], // 当前选中关联机构列表
+      selectAssClubListAll: [], // 全部选中关联机构列表
+      filterSelectAssClubList: [] // 筛选后的关联机构列表
+    }
+  },
+  computed: {
+    ...mapGetters(['authUserId', 'proxyInfo']),
+    // 级联选择器
+    cascaderProps() {
+      return {
+        lazy: true,
+        lazyLoad: async(node, resolve) => {
+          const { level, value = 0 } = node
+          const result = await getAddress({ parentId: value, type: level })
+          const nodes = result.data.map((item) => ({ value: item.id, label: item.name, leaf: level >= 2 }))
+          resolve(nodes)
+        }
+      }
+    },
+    cascaderDisplay() {
+      return this.formData.address.length > 0
+    },
+    cascaderPlaceholder() {
+      return this.cascaderDisplay ? this.area : '请选择所在区域'
+    },
+    // 定位使用的地址
+    locationAddress() {
+      // 广东省/深圳市/福田区景峰大厦
+      return this.address + this.formData.fullAddress
+    },
+    // 位置坐标
+    lnglat() {
+      return this.formData.point ? this.formData.point.split(',') : null
+    },
+    // 授权牌logo上传提示
+    authImageLogoUploadTip() {
+      return `限制尺寸:${this.validatorFields.authImageLogoWidth}px *${this.validatorFields.authImageLogoHeight}px`
+    }
+  },
+  created() {
+    this.editType = this.$route.query.type || 'add'
+    this.authId = this.$route.query.id
+    this.initFormData()
+    this.fetchAuthTempUsed()
+  },
+  methods: {
+    // 关联机构选择
+    onChooseAssClub() {
+      this.fetchAssClubList()
+      this.assClubListVisible = true
+    },
+    // 获取关联机构列表
+    async fetchAssClubList() {
+      try {
+        const excludeId = this.selectAssClubListAll.map((item) => item.authId)
+        if (this.authId) {
+          excludeId.push(parseInt(this.authId))
+        }
+        const res = await fecthAuthList(this.assClubQuery)
+        this.assClubList = res.data.list.filter((item) => !excludeId.includes(item.authId))
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    // 关联机构列表筛选
+    onFilterAssClubList(query) {
+      this.assClubQuery.authParty = query.authParty
+      this.fetchAssClubList()
+    },
+    // 关联机构列表选中
+    onAssClubListChange(value) {
+      this.selectAssClubList = value
+    },
+    // 关联机构选中列表确认
+    onAssClubListConfirm() {
+      this.selectAssClubListAll = [...this.selectAssClubListAll, ...this.selectAssClubList]
+      this.filterSelectAssClubList = this.selectAssClubListAll
+      this.assClubQuery.authParty = ''
+      this.assClubList = []
+      this.assClubListVisible = false
+    },
+    // 关联机构选中列表取消
+    onAssClubListCancel() {
+      this.selectAssClubList = []
+      this.filterSelectAssClubList = this.selectAssClubListAll
+      this.assClubQuery.authParty = ''
+      this.assClubList = []
+      this.assClubListVisible = false
+    },
+    // 已关联机构列表筛选
+    onFilterSelectAssClubList(query) {
+      if (query.authParty) {
+        this.filterSelectAssClubList = this.selectAssClubListAll.filter((item) =>
+          new RegExp(query.authParty, 'ig').test(item.authParty)
+        )
+      } else {
+        this.filterSelectAssClubList = this.selectAssClubListAll
+      }
+    },
+    // 已关联机构列表删除
+    onAssClubListRemove(row) {
+      this.selectAssClubListAll = this.selectAssClubListAll.filter((item) => item.authId !== row.authId)
+      this.filterSelectAssClubList = this.selectAssClubListAll
+    },
+
+    // 根据地址信息定位
+    async initGeocoder() {
+      try {
+        const geocoder = await initGeocoder()
+        return new Promise((resolve, reject) => {
+          geocoder.getLocation(this.locationAddress, (status, result) => {
+            if (status === 'complete' && result.info === 'OK') {
+              const position = result.geocodes[0].location
+              this.onPosition(position)
+              resolve()
+            } else {
+              console.log(result)
+              reject()
+            }
+          })
+        })
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // 地图定位
+    initMap() {
+      this.dialogMapVisible = true
+      this.$nextTick(() => {
+        this.$refs.aMap.init()
+      })
+    },
+
+    // 获取位置坐标
+    onPosition(lnglat) {
+      this.formData.point = `${lnglat.lng},${lnglat.lat}`
+    },
+
+    // 获取地址
+    initAddress() {
+      return getAddress({
+        parentId: 19,
+        type: 1
+      })
+    },
+
+    // 地图标记变化
+    markerChange(point) {
+      this.formData.point = `${point.lng},${point.lat}`
+    },
+
+    // 数据回显
+    initFormData() {
+      if (!this.authId) return
+      getAuthFormData({ authId: this.authId }).then((res) => {
+        console.log(res)
+        this.formData.authParty = res.data.authParty
+
+        this.formData.fullAddress = res.data.address
+        this.formData.point = res.data.lngAndLat
+        this.formData.mobile = res.data.mobile
+        this.formData.logo = res.data.logo || ''
+        this.formData.banner = res.data.bannerList.length || ''
+        this.formData.relationId = res.data.relationId
+        this.formData.relationName = res.data.relationName
+
+        this.formData.customFlag = res.data.customFlag
+        this.formData.remarks = res.data.remarks
+
+        if (res.data.logo) {
+          this.logoList = [{ name: '机构logo', url: res.data.logo }]
+        }
+
+        if (res.data.bannerList.length > 0) {
+          this.bannerList = res.data.bannerList.map((item, index) => ({ name: `门头照${index}`, url: item }))
+        }
+
+        this.formData.address = [res.data.provinceId, res.data.cityId, res.data.townId]
+        // this.formData.address = '广东省/深圳市/福田区'
+        this.area = res.data.area
+        this.address = res.data.area
+
+        this.formData.empNum = res.data.empNum
+        this.formData.firstClubType = res.data.firstClubType
+        this.formData.secondClubType = res.data.secondClubType
+
+        this.formData.medicalLicenseImage = res.data.medicalLicenseImage
+        if (res.data.medicalLicenseImage) {
+          this.licenseImageList = [{ name: '医疗许可证', url: res.data.medicalLicenseImage }]
+        }
+
+        this.formData.userMobile = res.data.userMobile
+
+        // 授权牌相关字段
+        this.formData.authCode = res.data.authCode
+        this.formData.authDate = res.data.authDate
+        this.formData.authImageType = res.data.authImageType
+
+        this.formData.authImageLogo = res.data.authImageLogo
+        if (res.data.authImageLogo) {
+          this.authImageLogoList = [{ name: '授权牌logo', url: res.data.authImageLogo }]
+        }
+
+        this.formData.authImage = res.data.authImage
+        if (res.data.authImage) {
+          this.authImageList = [{ name: '自定义授权牌', url: res.data.authImage }]
+        }
+
+        // 运营人相关
+        this.formData.linkMan = res.data.linkMan
+        this.formData.linkMobile = res.data.linkMobile
+
+        // 关联机构列表
+        if (res.data.releationClubList) {
+          this.selectAssClubListAll = res.data.releationClubList
+          this.filterSelectAssClubList = this.selectAssClubListAll
+        }
+
+        // 如果经纬度为空
+        if (!res.data.lngAndLat && this.locationAddress) {
+          this.initGeocoder()
+        }
+      })
+    },
+
+    // 表单提交保存
+    async submit() {
+      this.$refs.submitForm.validate(async(valide) => {
+        if (!valide) return
+
+        // 如果经纬度为空
+        if (!this.formData.point && this.locationAddress) {
+          await this.initGeocoder()
+        }
+
+        const {
+          authParty,
+          address: [provinceId, cityId, townId],
+          mobile,
+          logo,
+          point: lngAndLat,
+          customFlag,
+          remarks,
+          empNum,
+          firstClubType,
+          secondClubType,
+          medicalLicenseImage,
+          userMobile,
+          authCode,
+          authDate,
+          authImageType,
+          authImageLogo,
+          authImage,
+          linkMan,
+          linkMobile
+        } = this.formData
+
+        const authUserId = this.proxyInfo?.authUserId || this.authUserId
+
+        const data = {
+          authId: parseInt(this.authId),
+          authParty,
+          authUserId,
+          createBy: authUserId,
+          provinceId,
+          cityId,
+          townId,
+          address: this.formData.fullAddress,
+          mobile,
+          logo,
+          lngAndLat,
+          remarks,
+          customFlag,
+          empNum,
+          firstClubType,
+          secondClubType,
+          medicalLicenseImage,
+          userMobile,
+          authCode,
+          authDate: authDate ? formatDate(authDate, 'yyyy.MM.DD') : '',
+          authImageType,
+          authImageLogo,
+          authImage,
+          linkMan,
+          linkMobile,
+          relationId: this.selectAssClubListAll.map((item) => item.authId).join(','),
+          relationName: this.selectAssClubListAll.map((item) => item.authParty).join(',')
+        }
+
+        data.bannerList = this.bannerList.map((item) => (item.response ? item.response.data : item.url))
+
+        // const data = deepClone(this.formatDate)
+        // const [provinceId, cityId, townId] = this.formData.address
+        // const lngAndLat = this.formData.point
+
+        console.log(data)
+
+        // return
+        saveBrandAuth(data)
+          .then((res) => {
+            const h = this.$createElement
+            this.$notify.success({
+              title: `修改授权机构`,
+              message: h('i', { style: 'color: #333' }, `已修改授权机构:"${this.formData.authParty}"`),
+              duration: 3000
+            })
+            // this.$refs.submitForm.resetFields()
+            this.$store.dispatch('tagsView/delView', this.$route)
+            this.$router.push('/club/list')
+          })
+          .catch((err) => {
+            console.log(err)
+          })
+      })
+    },
+    handleChange(e) {
+      const node = this.$refs.cascader.getCheckedNodes()
+      if (node.length <= 0) return
+      this.address = node[0].pathLabels.join()
+      this.initGeocoder()
+    },
+
+    // 获取当前机构可用授权牌模板
+    async fetchAuthTempUsed() {
+      try {
+        const res = await authTempUsed({
+          authUserId: this.authUserId,
+          authFlag: 1,
+          status: 1
+        })
+        if (res.data) {
+          const [width, height] = res.data.logoSize.split(',')
+          this.validatorFields.authImageLogoWidth = width
+          this.validatorFields.authImageLogoHeight = height
+          this.authTempFlag = true
+        } else {
+          this.authTempFlag = false
+        }
+      } catch (error) {
+        console.log(error)
+      }
+    },
+
+    // logo上传
+    uploadLogoSuccess({ response, file, fileList }) {
+      this.logoList = fileList
+      this.formData.logo = fileList[0].response.data
+    },
+    handleLogoRemove({ file, fileList }) {
+      this.logoList = fileList
+      this.formData.logo = ''
+    },
+    beforeLogoUpload(file) {
+      const flag = file.size / 1024 < 500
+      if (!flag) {
+        this.$message.error('上传logo图片大小不能超过 500kb!')
+      }
+      return flag
+    },
+
+    // banner上传
+    uploadBannerSuccess({ response, file, fileList }) {
+      this.bannerList = fileList
+      console.log(this.bannerList)
+      this.formData.banner = fileList.length > 0 ? fileList.length : ''
+    },
+    handleBannerRemove({ file, fileList }) {
+      this.bannerList = fileList
+      this.formData.banner = fileList.length > 0 ? fileList.length : ''
+    },
+    beforeBannerUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('上传banner图片大小不能超过 1MB!')
+      }
+      return flag
+    },
+
+    // 医疗许可证图片上传
+    uploadLicenseImageSuccess({ response, file, fileList }) {
+      this.licenseImageList = fileList
+      console.log(this.licenseImageList)
+      this.formData.medicalLicenseImage = response.data
+    },
+    handleLicenseImageRemove({ file, fileList }) {
+      this.licenseImageList = fileList
+      this.formData.medicalLicenseImage = ''
+    },
+    beforeLicenseImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 1
+      if (!flag) {
+        this.$message.error('医疗许可证图片大小不能超过 1MB!')
+      }
+      return flag
+    },
+
+    // 授权牌照上传
+    beforeAuthImageUpload(file) {
+      const flag = file.size / 1024 / 1024 < 5
+      if (!flag) {
+        this.$message.error('上传授权牌图片大小不能超过 5MB!')
+      }
+      return flag
+    },
+    uploadAuthImageSuccess({ response, file, fileList }) {
+      this.authImageList = fileList
+      this.formData.authImage = response.data
+    },
+    handleAuthImageRemove({ file, fileList }) {
+      this.authImageList = fileList
+      this.formData.authImage = ''
+    },
+
+    // 授权牌logo上传
+    beforeAuthImageLogoUpload(file) {
+      return new Promise((resolve, reject) => {
+        if (file.size > 5 * 1024 * 1024) {
+          this.$message.error('授权牌logo图片大小不能超过 5MB!')
+          reject('图片大小超出最大限制')
+        }
+        const image = new Image()
+        image.src = URL.createObjectURL(file)
+        image.onload = (e) => {
+          const { naturalWidth, naturalHeight } = e.path ? e.path[0] : e.target
+          const { authImageLogoWidth: width, authImageLogoHeight: height } = this.validatorFields
+          if (naturalWidth > width || naturalHeight > height) {
+            this.$message.error('图片尺寸校验未通过')
+            reject('图片尺寸校验未通过')
+          } else {
+            resolve('图片尺寸校验通过')
+          }
+        }
+      })
+    },
+    uploadAuthImageLogoSuccess({ response, file, fileList }) {
+      this.authImageLogoList = fileList
+      this.formData.authImageLogo = response.data
+    },
+    handleAuthImageLogoRemove({ file, fileList }) {
+      this.authImageLogoList = fileList
+      this.formData.authImageLogo = ''
+    },
+    // 输入手机号时
+    onMobileInput() {
+      this.formData.mobile = this.formData.mobile.replace(/[^\w\.\/]/gi, '')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+#allmap {
+  width: 100%;
+  height: 600px;
+}
+
+.attributes {
+  padding-top: 16px;
+}
+</style>

+ 90 - 772
src/views/normal/club/edit.vue

@@ -1,407 +1,50 @@
 <template>
 <template>
   <div class="club-edit page-form-container">
   <div class="club-edit page-form-container">
-    <el-form ref="submitForm" label-width="140px" :model="formData" :rules="rules">
-      <el-form-item label="机构名称:" prop="authParty">
-        <el-input v-model="formData.authParty" placeholder="请输入机构名称" clearable />
-      </el-form-item>
-      <el-form-item label="所在地区:" prop="address">
-        <el-cascader
-          ref="cascader"
-          v-model="formData.address"
-          :class="{ display: cascaderDisplay }"
-          clearable
-          :props="cascaderProps"
-          style="width: 100%"
-          :placeholder="cascaderPlaceholder"
-          @change="handleChange"
-        />
-      </el-form-item>
-      <el-form-item label="详细地址:" prop="fullAddress">
-        <el-input v-model="formData.fullAddress" placeholder="请输入详细地址" clearable @blur="initGeocoder" />
-      </el-form-item>
-      <el-form-item label="经纬度:" prop="point">
-        <el-input
-          v-model="formData.point"
-          placeholder="请输入经纬度 (格式:纬度,经度,可通过右侧地图小按钮获取)"
-          clearable
-        >
-          <el-button slot="append" icon="el-icon-map-location" @click="initMap" />
-        </el-input>
-      </el-form-item>
-      <el-form-item label="联系电话:">
-        <el-input v-model="formData.mobile" placeholder="请输入联系方式" clearable />
-      </el-form-item>
-
-      <el-form-item label="运营联系人:">
-        <el-input v-model="formData.linkMan" placeholder="请输入运营联系人" clearable />
-      </el-form-item>
-
-      <el-form-item label="运营联系人手机号:">
-        <el-input
-          v-model="formData.linkMobile"
-          placeholder="请输入运营联系人手机号"
-          clearable
-          maxlength="11"
-          show-word-limit
-          @input="onMobileInput"
-        />
-      </el-form-item>
-
-      <el-form-item label="认证编号:" prop="authCode">
-        <el-input v-model="formData.authCode" placeholder="请输认证编号" clearable />
-      </el-form-item>
-
-      <el-form-item label="认证日期:" prop="authDate">
-        <el-date-picker v-model="formData.authDate" type="date" placeholder="选择日期" style="width: 100%" />
-      </el-form-item>
-      <!-- <el-form-item label="手机号:" prop="userMobile">
-        <el-input v-model="formData.userMobile" placeholder="请输入手机号" clearable maxlength="11" show-word-limit />
-      </el-form-item> -->
-      <el-form-item label="机构logo:" prop="logo">
-        <el-input v-show="false" v-model="formData.logo" />
-        <upload-image
-          tip="建议尺寸:242px * 242px"
-          :image-list="logoList"
-          :before-upload="beforeLogoUpload"
-          @success="uploadLogoSuccess"
-          @remove="handleLogoRemove"
-        />
-      </el-form-item>
-      <el-form-item label="门头照:" prop="banner">
-        <div class="form-label-tip">至少上传一张机构门店图,最多上传6张)</div>
-        <el-input v-show="false" v-model="formData.banner" />
-        <upload-image
-          tip="至少上传一张,最多6张;建议尺寸:542px * 542px"
-          :image-list="bannerList"
-          :before-upload="beforeBannerUpload"
-          :limit="6"
-          @success="uploadBannerSuccess"
-          @remove="handleBannerRemove"
-        />
-      </el-form-item>
-
-      <!-- **************** 新方法配置授权牌 START ******************* -->
-      <el-form-item label="授权牌:">
-        <el-radio-group v-model="formData.authImageType" size="mini">
-          <el-radio :label="1" border>模板库生成</el-radio>
-          <el-radio :label="2" border>自定义上传</el-radio>
-        </el-radio-group>
-        <div style="margin-top: 12px">
-          <template v-if="formData.authImageType === 2">
-            <upload-image
-              tip="建议尺寸:542px * 546px"
-              :image-list="authImageList"
-              :before-upload="beforeAuthImageUpload"
-              @success="uploadAuthImageSuccess"
-              @remove="handleAuthImageRemove"
-            />
-            <el-input v-show="false" v-model="formData.authImage" />
-          </template>
-          <template v-else>
-            <template v-if="authTempFlag">
-              <preview-image v-if="formData.authImage" width="148px" height="148px" :src="formData.authImage" />
-            </template>
-            <template v-else>无</template>
-          </template>
-        </div>
-      </el-form-item>
-
-      <el-form-item v-if="authTempFlag && formData.authImageType === 1" label="授权牌logo:">
-        <div class="form-label-tip">授权牌logo(提示:授权牌logo与机构名称组合)</div>
-        <div style="margin-top: 8px">
-          <upload-image
-            :tip="authImageLogoUploadTip"
-            :image-list="authImageLogoList"
-            :before-upload="beforeAuthImageLogoUpload"
-            @success="uploadAuthImageLogoSuccess"
-            @remove="handleAuthImageLogoRemove"
-          />
-          <el-input v-show="false" v-model="formData.authImageLogo" />
-        </div>
-      </el-form-item>
-
-      <!-- **************** 新方法配置授权牌 End ******************* -->
-
-      <el-form-item label="机构类型:">
-        <el-radio-group v-model="formData.firstClubType">
-          <el-radio :label="1">医美</el-radio>
-          <el-radio :label="2">生美</el-radio>
-          <el-radio :label="3">项目公司</el-radio>
-          <el-radio :label="4">个人</el-radio>
-          <el-radio :label="5">其他</el-radio>
-        </el-radio-group>
-      </el-form-item>
-
-      <el-form-item v-if="formData.firstClubType === 1" label="医美类型:">
-        <el-radio-group v-model="formData.secondClubType">
-          <el-radio :label="1">诊所</el-radio>
-          <el-radio :label="2">门诊</el-radio>
-          <el-radio :label="3">医院</el-radio>
-          <el-radio :label="4">其他</el-radio>
-        </el-radio-group>
-      </el-form-item>
-
-      <el-form-item v-if="formData.firstClubType === 2" label="生美类型:">
-        <el-radio-group v-model="formData.secondClubType">
-          <el-radio :label="5">美容院</el-radio>
-          <el-radio :label="6">养生馆</el-radio>
-          <el-radio :label="7">其他</el-radio>
-        </el-radio-group>
-      </el-form-item>
-
-      <el-form-item v-if="formData.firstClubType === 1" label="医疗许可证:" prop="medicalLicenseImage">
-        <el-input v-show="false" v-model="formData.medicalLicenseImage" />
-        <upload-image
-          tip="请上传医疗许可证;建议尺寸:542px * 542px"
-          :limit="1"
-          :image-list="licenseImageList"
-          :before-upload="beforeLicenseImageUpload"
-          @success="uploadLicenseImageSuccess"
-          @remove="handleLicenseImageRemove"
-        />
-      </el-form-item>
-
-      <el-form-item label="员工人数:" prop="empNum">
-        <el-input v-model.number="formData.empNum" placeholder="请输入员工人数" clearable />
-      </el-form-item>
-
-      <el-form-item label="自定义属性:">
-        <el-radio-group v-model="formData.customFlag" size="mini">
-          <el-radio :label="0" border>否</el-radio>
-          <el-radio :label="1" border>是</el-radio>
-        </el-radio-group>
-      </el-form-item>
-
-      <template v-if="formData.customFlag === 1">
-        <el-form-item label="店铺备注:" prop="remarks">
-          <el-input v-model="formData.remarks" placeholder="店铺备注" clearable />
-        </el-form-item>
-      </template>
-
-      <el-form-item label="已关联机构:">
-        <el-button size="mini" type="primary" @click="onChooseAssClub">关联机构</el-button>
-      </el-form-item>
-      <el-form-item>
-        <associated-club-list
-          :selection="false"
-          :control="true"
-          :list="filterSelectAssClubList"
-          @filter="onFilterSelectAssClubList"
-        >
-          <template #control="{ row }">
-            <el-button size="mini" type="danger" @click="onAssClubListRemove(row)">删除</el-button>
-          </template>
-        </associated-club-list>
-      </el-form-item>
-    </el-form>
+    <el-tabs v-model="activeName">
+      <el-tab-pane label="基础资料" name="first">
+        <ClubBasicsInfo ref="ClubBasicsInfo" />
+      </el-tab-pane>
+      <el-tab-pane label="授权牌资料" name="second">
+        <ClubAuthorizeBrand ref="ClubAuthorizeBrand" />
+      </el-tab-pane>
+      <el-tab-pane label="机构关联" name="third">
+        <ClubAssociated ref="ClubAssociated" />
+      </el-tab-pane>
+      <el-tab-pane label="特殊属性" name="fourth">
+        <ClubSpecialInfo ref="ClubSpecialInfo" />
+      </el-tab-pane>
+    </el-tabs>
 
 
     <!-- 表单提交 返回 -->
     <!-- 表单提交 返回 -->
     <div class="control-box">
     <div class="control-box">
       <el-button type="primary" @click="submit">保存</el-button>
       <el-button type="primary" @click="submit">保存</el-button>
       <el-button type="warning" @click="navigateBack">返回</el-button>
       <el-button type="warning" @click="navigateBack">返回</el-button>
     </div>
     </div>
-
-    <!-- 地图坐标拾取 -->
-    <el-dialog
-      class="map-dialog"
-      title="坐标拾取(请拖动标记点选取准确位置)"
-      :visible.sync="dialogMapVisible"
-      width="80%"
-    >
-      <a-map ref="aMap" :lnglat="lnglat" :address="locationAddress" @position="onPosition" />
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" size="mini" @click="dialogMapVisible = false">确 定</el-button>
-      </div>
-    </el-dialog>
-
-    <!-- 关联机构 -->
-    <el-dialog title="添加关联机构" :visible.sync="assClubListVisible" width="30%" :show-close="false">
-      <associated-club-list
-        v-if="assClubListVisible"
-        :selection="true"
-        :control="false"
-        height="280"
-        :list="assClubList"
-        @filter="onFilterAssClubList"
-        @selected="onAssClubListChange"
-      />
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" size="mini" @click="onAssClubListCancel">取 消</el-button>
-        <el-button type="primary" size="mini" @click="onAssClubListConfirm">确 定</el-button>
-      </div>
-    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
-import SimpleAMap from '@/components/SimpleAMap'
-import UploadImage from '@/components/UploadImage'
-import { AssociatedClubList } from '@/views/components/index'
-import { mapGetters } from 'vuex'
-import { saveBrandAuth, getAuthFormData, fecthAuthList } from '@/api/auth'
-import { getAddress } from '@/api/common'
-import { isMobile, isNumber } from '@/utils/validate'
+import { getAuthFormData, saveBrandAuth } from '@/api/auth'
+import { ClubAssociated, ClubBasicsInfo, ClubAuthorizeBrand, ClubSpecialInfo } from './components/index'
 import { formatDate } from '@/utils'
 import { formatDate } from '@/utils'
-import { authTempUsed } from '@/api/system'
-import { initGeocoder } from '@/components/SimpleAMap/common/utils'
-
+import { mapGetters } from 'vuex'
 export default {
 export default {
+  name: 'ClubEdit',
   components: {
   components: {
-    [SimpleAMap.name]: SimpleAMap,
-    UploadImage,
-    AssociatedClubList
+    ClubAssociated,
+    ClubBasicsInfo,
+    ClubAuthorizeBrand,
+    ClubSpecialInfo
   },
   },
   data() {
   data() {
-    // var validatePoint = (rule, value, callback) => {
-    //   if (value === '') {
-    //     callback(new Error('经纬度坐标不能为空'))
-    //   } else {
-    //     if (isPoint(value)) {
-    //       callback()
-    //     } else {
-    //       callback(new Error('经纬度坐标格式不正确,(例如:114.095294,22.536004)'))
-    //     }
-    //   }
-    // }
-
-    var validateMobile = (rule, value, callback) => {
-      if (value === '') {
-        callback(new Error('联系方式不能为空'))
-      } else {
-        if (isNumber(value)) {
-          callback()
-        } else {
-          callback(new Error('联系方式格式不正确'))
-        }
-      }
-    }
-
-    var validatePhoneNumber = (rule, value, callback) => {
-      if (!value || isMobile(value)) {
-        callback()
-      } else {
-        callback(new Error('手机号格式不正确'))
-      }
-    }
-
     return {
     return {
       editType: 'add',
       editType: 'add',
-      dialogMapVisible: false,
-      point: {},
-      value: [],
-      options: [],
-
-      assClubListVisible: false,
-
       authId: '',
       authId: '',
-      disabled: false,
-      area: '',
-      formData: {
-        authParty: '',
-        address: [],
-        fullAddress: '',
-        point: '',
-        mobile: '',
-        userMobile: '',
-        logo: '',
-        banner: '',
-        customFlag: 0,
-        remarks: '',
-        empNum: '',
-        firstClubType: 1,
-        secondClubType: 1,
-        medicalLicenseImage: '',
-        // 新增授权牌字段
-        authCode: '',
-        authDate: '',
-        authImageType: 1,
-        authImageLogo: '',
-        authImage: '',
-        // 新增运营人字段
-        linkMan: '',
-        linkMobile: '',
-        // 机构关联
-        relationId: '',
-        relationName: ''
-      },
-      rules: {
-        authParty: [{ required: true, message: '机构名称不能为空', trigger: ['blur', 'change'] }],
-        address: [{ required: true, message: '地址不能为空', trigger: 'change', type: 'array' }],
-        fullAddress: [{ required: true, message: '详细不能为空', trigger: ['blur', 'change'] }],
-        // point: [{ required: true, validator: validatePoint, trigger: ['blur', 'change'] }],
-        mobile: [{ required: true, validator: validateMobile, trigger: ['blur', 'change'] }],
-        logo: [{ required: true, message: '请上传机构logo', trigger: 'change' }],
-        banner: [{ required: true, message: '请至少上传一张banner图片', trigger: 'change' }],
-        remarks: [{ required: true, message: '店铺备注不能为空', trigger: 'blur' }],
-        medicalLicenseImage: [{ required: true, message: '请上传医疗许可证', trigger: 'change' }],
-        empNum: [{ required: true, message: '员工人数不能为空', trigger: 'change' }],
-        userMobile: [{ validator: validatePhoneNumber, trigger: 'change' }],
-        authImageLogo: [{ required: true, message: '请上传授权牌logo', trigger: 'change' }]
-      },
-      // logo图片列表
-      logoList: [],
-      // banner图片列表
-      bannerList: [],
-      // 级联选择的地址
-      address: '',
-      // 医疗许可证图片
-      licenseImageList: [],
-      // 授权牌照图片列表
-      authImageList: [],
-      // 授权牌logo列表
-      authImageLogoList: [],
-      // 验证
-      validatorFields: {
-        authImageLogoWidth: 100,
-        authImageLogoHeight: 100
-      },
-      // 授权牌模板标识
-      authTempFlag: false,
-      // 关联机构相关
-      assClubQuery: {
-        pageNum: 1,
-        pageSize: 1000,
-        authParty: ''
-      },
-      assClubList: [], // 关联机构列表
-      selectAssClubList: [], // 当前选中关联机构列表
-      selectAssClubListAll: [], // 全部选中关联机构列表
-      filterSelectAssClubList: [] // 筛选后的关联机构列表
+      activeName: 'first'
     }
     }
   },
   },
   computed: {
   computed: {
-    ...mapGetters(['authUserId', 'proxyInfo']),
-    // 级联选择器
-    cascaderProps() {
-      return {
-        lazy: true,
-        lazyLoad: async(node, resolve) => {
-          const { level, value = 0 } = node
-          const result = await getAddress({ parentId: value, type: level })
-          const nodes = result.data.map((item) => ({ value: item.id, label: item.name, leaf: level >= 2 }))
-          resolve(nodes)
-        }
-      }
-    },
-    cascaderDisplay() {
-      return this.formData.address.length > 0
-    },
-    cascaderPlaceholder() {
-      return this.cascaderDisplay ? this.area : '请选择所在区域'
-    },
-    // 定位使用的地址
-    locationAddress() {
-      // 广东省/深圳市/福田区景峰大厦
-      return this.address + this.formData.fullAddress
-    },
-    // 位置坐标
-    lnglat() {
-      return this.formData.point ? this.formData.point.split(',') : null
-    },
-    // 授权牌logo上传提示
-    authImageLogoUploadTip() {
-      return `限制尺寸:${this.validatorFields.authImageLogoWidth}px *${this.validatorFields.authImageLogoHeight}px`
-    }
+    ...mapGetters(['authUserId', 'proxyInfo'])
   },
   },
   created() {
   created() {
     this.editType = this.$route.query.type || 'add'
     this.editType = this.$route.query.type || 'add'
@@ -410,418 +53,93 @@ export default {
     this.fetchAuthTempUsed()
     this.fetchAuthTempUsed()
   },
   },
   methods: {
   methods: {
-    // 关联机构选择
-    onChooseAssClub() {
-      this.fetchAssClubList()
-      this.assClubListVisible = true
-    },
-    // 获取关联机构列表
-    async fetchAssClubList() {
+    // 提交表单数据
+    async submit() {
+      // 验证表单
+      const first = this.$refs.ClubBasicsInfo.validateForm()
+      const second = this.$refs.ClubAuthorizeBrand.validateForm()
+      const third = this.$refs.ClubAssociated.validateForm()
+      const fourth = this.$refs.ClubSpecialInfo.validateForm()
       try {
       try {
-        const excludeId = this.selectAssClubListAll.map((item) => item.authId)
-        if (this.authId) {
-          excludeId.push(parseInt(this.authId))
-        }
-        const res = await fecthAuthList(this.assClubQuery)
-        this.assClubList = res.data.list.filter((item) => !excludeId.includes(item.authId))
+        const formData = {}
+        const result = await Promise.all([first, second, third, fourth])
+        console.log(result)
+        result.forEach((item) => Object.assign(formData, item))
+        this.save(formData)
       } catch (error) {
       } catch (error) {
         console.log(error)
         console.log(error)
       }
       }
     },
     },
-    // 关联机构列表筛选
-    onFilterAssClubList(query) {
-      this.assClubQuery.authParty = query.authParty
-      this.fetchAssClubList()
-    },
-    // 关联机构列表选中
-    onAssClubListChange(value) {
-      this.selectAssClubList = value
-    },
-    // 关联机构选中列表确认
-    onAssClubListConfirm() {
-      this.selectAssClubListAll = [...this.selectAssClubListAll, ...this.selectAssClubList]
-      this.filterSelectAssClubList = this.selectAssClubListAll
-      this.assClubQuery.authParty = ''
-      this.assClubList = []
-      this.assClubListVisible = false
-    },
-    // 关联机构选中列表取消
-    onAssClubListCancel() {
-      this.selectAssClubList = []
-      this.filterSelectAssClubList = this.selectAssClubListAll
-      this.assClubQuery.authParty = ''
-      this.assClubList = []
-      this.assClubListVisible = false
-    },
-    // 已关联机构列表筛选
-    onFilterSelectAssClubList(query) {
-      if (query.authParty) {
-        this.filterSelectAssClubList = this.selectAssClubListAll.filter((item) =>
-          new RegExp(query.authParty, 'ig').test(item.authParty)
-        )
-      } else {
-        this.filterSelectAssClubList = this.selectAssClubListAll
-      }
-    },
-    // 已关联机构列表删除
-    onAssClubListRemove(row) {
-      this.selectAssClubListAll = this.selectAssClubListAll.filter((item) => item.authId !== row.authId)
-      this.filterSelectAssClubList = this.selectAssClubListAll
-    },
-
-    // 根据地址信息定位
-    async initGeocoder() {
+    // 保存表单数据
+    async save(formData) {
+      console.log(formData)
+      const params = Object.create(null)
+      const [provinceId, cityId, townId] = formData.address
+      params.authId = Number(this.authId)
+      params.authParty = formData.authParty
+      params.authUserId = this.authUserId
+      params.createBy = this.authUserId
+      params.provinceId = provinceId
+      params.cityId = cityId
+      params.townId = townId
+      params.address = formData.fullAddress
+      params.mobile = formData.mobile
+      params.logo = formData.logo
+      params.lngAndLat = formData.point
+      params.remarks = formData.remarks
+      params.customFlag = formData.customFlag
+      params.empNum = formData.empNum
+      params.firstClubType = formData.firstClubType
+      params.secondClubType = formData.secondClubType
+      params.medicalLicenseImage = formData.medicalLicenseImage
+      params.userMobile = formData.userMobile
+      params.authCode = formData.authCode
+      params.authDate = formData.authDate ? formatDate(formData.authDate, 'yyyy.MM.DD') : ''
+      params.authImageType = formData.authImageType
+      params.authImageLogo = formData.authImageLogo
+      params.authImage = formData.authImage
+      params.linkMan = formData.linkMan
+      params.linkMobile = formData.linkMobile
+      params.relationId = formData.selectAssClubListAll.map((item) => item.authId).join(',')
+      params.relationName = formData.selectAssClubListAll.map((item) => item.authParty).join(',')
+      params.bannerList = formData.bannerList.map((item) => (item.response ? item.response.data : item.url))
+      // 保存
       try {
       try {
-        const geocoder = await initGeocoder()
-        return new Promise((resolve, reject) => {
-          geocoder.getLocation(this.locationAddress, (status, result) => {
-            if (status === 'complete' && result.info === 'OK') {
-              const position = result.geocodes[0].location
-              this.onPosition(position)
-              resolve()
-            } else {
-              console.log(result)
-              reject()
-            }
-          })
+        console.log(params)
+        await saveBrandAuth(params)
+        const h = this.$createElement
+        this.$notify.success({
+          title: `修改授权机构`,
+          message: h('i', { style: 'color: #333' }, `已修改授权机构:"${params.authParty}"`),
+          duration: 3000
         })
         })
+        this.$store.dispatch('tagsView/delView', this.$route)
+        this.$router.push('/club/list')
       } catch (error) {
       } catch (error) {
         console.log(error)
         console.log(error)
       }
       }
     },
     },
-
-    // 地图定位
-    initMap() {
-      this.dialogMapVisible = true
-      this.$nextTick(() => {
-        this.$refs.aMap.init()
-      })
-    },
-
-    // 获取位置坐标
-    onPosition(lnglat) {
-      this.formData.point = `${lnglat.lng},${lnglat.lat}`
-    },
-
-    // 获取地址
-    initAddress() {
-      return getAddress({
-        parentId: 19,
-        type: 1
-      })
-    },
-
-    // 地图标记变化
-    markerChange(point) {
-      this.formData.point = `${point.lng},${point.lat}`
-    },
-
-    // 数据回显
+    // 初始化机构数据
     initFormData() {
     initFormData() {
       if (!this.authId) return
       if (!this.authId) return
       getAuthFormData({ authId: this.authId }).then((res) => {
       getAuthFormData({ authId: this.authId }).then((res) => {
-        console.log(res)
-        this.formData.authParty = res.data.authParty
-
-        this.formData.fullAddress = res.data.address
-        this.formData.point = res.data.lngAndLat
-        this.formData.mobile = res.data.mobile
-        this.formData.logo = res.data.logo || ''
-        this.formData.banner = res.data.bannerList.length || ''
-        this.formData.relationId = res.data.relationId
-        this.formData.relationName = res.data.relationName
-
-        this.formData.customFlag = res.data.customFlag
-        this.formData.remarks = res.data.remarks
-
-        if (res.data.logo) {
-          this.logoList = [{ name: '机构logo', url: res.data.logo }]
-        }
-
-        if (res.data.bannerList.length > 0) {
-          this.bannerList = res.data.bannerList.map((item, index) => ({ name: `门头照${index}`, url: item }))
-        }
-
-        this.formData.address = [res.data.provinceId, res.data.cityId, res.data.townId]
-        // this.formData.address = '广东省/深圳市/福田区'
-        this.area = res.data.area
-        this.address = res.data.area
-
-        this.formData.empNum = res.data.empNum
-        this.formData.firstClubType = res.data.firstClubType
-        this.formData.secondClubType = res.data.secondClubType
-
-        this.formData.medicalLicenseImage = res.data.medicalLicenseImage
-        if (res.data.medicalLicenseImage) {
-          this.licenseImageList = [{ name: '医疗许可证', url: res.data.medicalLicenseImage }]
-        }
-
-        this.formData.userMobile = res.data.userMobile
-
-        // 授权牌相关字段
-        this.formData.authCode = res.data.authCode
-        this.formData.authDate = res.data.authDate
-        this.formData.authImageType = res.data.authImageType
-
-        this.formData.authImageLogo = res.data.authImageLogo
-        if (res.data.authImageLogo) {
-          this.authImageLogoList = [{ name: '授权牌logo', url: res.data.authImageLogo }]
-        }
-
-        this.formData.authImage = res.data.authImage
-        if (res.data.authImage) {
-          this.authImageList = [{ name: '自定义授权牌', url: res.data.authImage }]
-        }
-
-        // 运营人相关
-        this.formData.linkMan = res.data.linkMan
-        this.formData.linkMobile = res.data.linkMobile
-
-        // 关联机构列表
-        if (res.data.releationClubList) {
-          this.selectAssClubListAll = res.data.releationClubList
-          this.filterSelectAssClubList = this.selectAssClubListAll
-        }
-
-        // 如果经纬度为空
-        if (!res.data.lngAndLat && this.locationAddress) {
-          this.initGeocoder()
-        }
-      })
-    },
-
-    // 表单提交保存
-    async submit() {
-      this.$refs.submitForm.validate(async(valide) => {
-        if (!valide) return
-
-        // 如果经纬度为空
-        if (!this.formData.point && this.locationAddress) {
-          await this.initGeocoder()
-        }
-
-        const {
-          authParty,
-          address: [provinceId, cityId, townId],
-          mobile,
-          logo,
-          point: lngAndLat,
-          customFlag,
-          remarks,
-          empNum,
-          firstClubType,
-          secondClubType,
-          medicalLicenseImage,
-          userMobile,
-          authCode,
-          authDate,
-          authImageType,
-          authImageLogo,
-          authImage,
-          linkMan,
-          linkMobile
-        } = this.formData
-
-        const authUserId = this.proxyInfo?.authUserId || this.authUserId
-
-        const data = {
-          authId: parseInt(this.authId),
-          authParty,
-          authUserId,
-          createBy: authUserId,
-          provinceId,
-          cityId,
-          townId,
-          address: this.formData.fullAddress,
-          mobile,
-          logo,
-          lngAndLat,
-          remarks,
-          customFlag,
-          empNum,
-          firstClubType,
-          secondClubType,
-          medicalLicenseImage,
-          userMobile,
-          authCode,
-          authDate: authDate ? formatDate(authDate, 'yyyy.MM.DD') : '',
-          authImageType,
-          authImageLogo,
-          authImage,
-          linkMan,
-          linkMobile,
-          relationId: this.selectAssClubListAll.map((item) => item.authId).join(','),
-          relationName: this.selectAssClubListAll.map((item) => item.authParty).join(',')
-        }
-
-        data.bannerList = this.bannerList.map((item) => (item.response ? item.response.data : item.url))
-
-        // const data = deepClone(this.formatDate)
-        // const [provinceId, cityId, townId] = this.formData.address
-        // const lngAndLat = this.formData.point
-
-        console.log(data)
-
-        // return
-        saveBrandAuth(data)
-          .then((res) => {
-            const h = this.$createElement
-            this.$notify.success({
-              title: `修改授权机构`,
-              message: h('i', { style: 'color: #333' }, `已修改授权机构:"${this.formData.authParty}"`),
-              duration: 3000
-            })
-            // this.$refs.submitForm.resetFields()
-            this.$store.dispatch('tagsView/delView', this.$route)
-            this.$router.push('/club/list')
-          })
-          .catch((err) => {
-            console.log(err)
-          })
+        this.$refs.ClubBasicsInfo.initForm(res.data)
+        this.$refs.ClubAuthorizeBrand.initForm(res.data)
+        this.$refs.ClubAssociated.initForm(res.data)
+        this.$refs.ClubSpecialInfo.initForm(res.data)
       })
       })
     },
     },
-    handleChange(e) {
-      const node = this.$refs.cascader.getCheckedNodes()
-      if (node.length <= 0) return
-      this.address = node[0].pathLabels.join()
-      this.initGeocoder()
-    },
-
-    // 获取当前机构可用授权牌模板
-    async fetchAuthTempUsed() {
-      try {
-        const res = await authTempUsed({
-          authUserId: this.authUserId,
-          authFlag: 1,
-          status: 1
-        })
-        if (res.data) {
-          const [width, height] = res.data.logoSize.split(',')
-          this.validatorFields.authImageLogoWidth = width
-          this.validatorFields.authImageLogoHeight = height
-          this.authTempFlag = true
-        } else {
-          this.authTempFlag = false
-        }
-      } catch (error) {
-        console.log(error)
-      }
-    },
-
-    // logo上传
-    uploadLogoSuccess({ response, file, fileList }) {
-      this.logoList = fileList
-      this.formData.logo = fileList[0].response.data
-    },
-    handleLogoRemove({ file, fileList }) {
-      this.logoList = fileList
-      this.formData.logo = ''
-    },
-    beforeLogoUpload(file) {
-      const flag = file.size / 1024 < 500
-      if (!flag) {
-        this.$message.error('上传logo图片大小不能超过 500kb!')
-      }
-      return flag
-    },
-
-    // banner上传
-    uploadBannerSuccess({ response, file, fileList }) {
-      this.bannerList = fileList
-      console.log(this.bannerList)
-      this.formData.banner = fileList.length > 0 ? fileList.length : ''
-    },
-    handleBannerRemove({ file, fileList }) {
-      this.bannerList = fileList
-      this.formData.banner = fileList.length > 0 ? fileList.length : ''
-    },
-    beforeBannerUpload(file) {
-      const flag = file.size / 1024 / 1024 < 1
-      if (!flag) {
-        this.$message.error('上传banner图片大小不能超过 1MB!')
-      }
-      return flag
-    },
-
-    // 医疗许可证图片上传
-    uploadLicenseImageSuccess({ response, file, fileList }) {
-      this.licenseImageList = fileList
-      console.log(this.licenseImageList)
-      this.formData.medicalLicenseImage = response.data
-    },
-    handleLicenseImageRemove({ file, fileList }) {
-      this.licenseImageList = fileList
-      this.formData.medicalLicenseImage = ''
-    },
-    beforeLicenseImageUpload(file) {
-      const flag = file.size / 1024 / 1024 < 1
-      if (!flag) {
-        this.$message.error('医疗许可证图片大小不能超过 1MB!')
-      }
-      return flag
-    },
-
-    // 授权牌照上传
-    beforeAuthImageUpload(file) {
-      const flag = file.size / 1024 / 1024 < 5
-      if (!flag) {
-        this.$message.error('上传授权牌图片大小不能超过 5MB!')
-      }
-      return flag
-    },
-    uploadAuthImageSuccess({ response, file, fileList }) {
-      this.authImageList = fileList
-      this.formData.authImage = response.data
-    },
-    handleAuthImageRemove({ file, fileList }) {
-      this.authImageList = fileList
-      this.formData.authImage = ''
-    },
-
-    // 授权牌logo上传
-    beforeAuthImageLogoUpload(file) {
-      return new Promise((resolve, reject) => {
-        if (file.size > 5 * 1024 * 1024) {
-          this.$message.error('授权牌logo图片大小不能超过 5MB!')
-          reject('图片大小超出最大限制')
-        }
-        const image = new Image()
-        image.src = URL.createObjectURL(file)
-        image.onload = (e) => {
-          const { naturalWidth, naturalHeight } = e.path ? e.path[0] : e.target
-          const { authImageLogoWidth: width, authImageLogoHeight: height } = this.validatorFields
-          if (naturalWidth > width || naturalHeight > height) {
-            this.$message.error('图片尺寸校验未通过')
-            reject('图片尺寸校验未通过')
-          } else {
-            resolve('图片尺寸校验通过')
-          }
-        }
-      })
-    },
-    uploadAuthImageLogoSuccess({ response, file, fileList }) {
-      this.authImageLogoList = fileList
-      this.formData.authImageLogo = response.data
-    },
-    handleAuthImageLogoRemove({ file, fileList }) {
-      this.authImageLogoList = fileList
-      this.formData.authImageLogo = ''
-    },
-    // 输入手机号时
-    onMobileInput() {
-      this.formData.mobile = this.formData.mobile.replace(/[^\w\.\/]/gi, '')
-    }
+    // 获取授权牌模板
+    fetchAuthTempUsed() {}
   }
   }
 }
 }
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
-#allmap {
-  width: 100%;
-  height: 600px;
+.el-tab-pane {
+  margin-top: 24px;
 }
 }
-
-.attributes {
-  padding-top: 16px;
+.page-form-container {
+  padding: 60px 0;
 }
 }
 </style>
 </style>

+ 149 - 0
src/views/normal/personalized/banner.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="app-container">
+    <!--
+      使用element-ui表单
+      可以保存banner,移动端banner和pc端banner单独上传
+      跳转方式支持无、上传图片、链接,图片支持单独上传
+    -->
+    <div class="form-container">
+      <el-form ref="form" :model="form" :rules="rules" label-width="140px">
+        <el-form-item label="移动端banner:" prop="pcImage">
+          <div class="banner" :style="pcImageStyle">
+            <img v-if="pcImage" :src="pcImage">
+            <span class="tip">请上传图片(1920*530px)</span>
+          </div>
+        </el-form-item>
+        <el-form-item label="PC端banner:" prop="appImage">
+          <div class="banner" :style="mobileImageStyle">
+            <img v-if="appImage" :src="appImage">
+            <span class="tip">请上传图片(800*800px)</span>
+          </div>
+        </el-form-item>
+        <el-form-item label="跳转方式:" prop="region">
+          <el-radio-group v-model="form.region">
+            <el-radio :label="0">无</el-radio>
+            <el-radio :label="1">图片</el-radio>
+            <el-radio :label="2">链接</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="form.region === 1" label="跳转图片:" prop="linkImage">
+          <UploadImage
+            :image-list="linkImageList"
+            :limit="1"
+            @success="uploadLinkImageSuccess"
+            @remove="handleLinkImageRemove"
+          />
+        </el-form-item>
+        <el-form-item v-if="form.region === 2" label="跳转链接:" prop="link">
+          <el-input v-model="form.link" />
+        </el-form-item>
+      </el-form>
+
+      <!-- 表单提交 返回 -->
+      <div class="control-box">
+        <el-button type="primary" @click="submit">保存</el-button>
+        <el-button type="warning" @click="navigateBack">返回</el-button>
+      </div>
+    </div>
+
+    <UploadImage v-show="false" @success="uploadImageSuccess" @remove="handleImageRemove" />
+  </div>
+</template>
+
+<script>
+import UploadImage from '@/components/UploadImage'
+export default {
+  name: 'PersonalBanner',
+  components: {
+    UploadImage
+  },
+  data() {
+    return {
+      form: {
+        region: 0,
+        link: '',
+        pcImage: '',
+        appImage: '',
+        linkImage: ''
+      },
+      rules: {
+        pcImage: [{ required: true, message: '请上传图片', trigger: 'change' }],
+        appImage: [{ required: true, message: '请上传图片', trigger: 'change' }],
+        linkImage: [{ required: true, message: '请上传图片', trigger: 'change' }],
+        link: [{ required: true, message: '请输入链接', trigger: 'blur' }]
+      },
+      linkImageList: []
+    }
+  },
+  computed: {
+    pcImageStyle() {
+      const scale = 0.32
+      return {
+        width: 1920 * scale + 'px',
+        height: 530 * scale + 'px'
+      }
+    },
+    mobileImageStyle() {
+      const scale = 0.32
+      return {
+        width: 1000 * scale + 'px',
+        height: 1000 * scale + 'px'
+      }
+    }
+  },
+  methods: {
+    submit() {},
+    uploadImageSuccess({ response, file, fileList }) {
+      this.imageList = fileList
+      this.formData.linkImage = fileList.length > 0 ? fileList.length : ''
+    },
+    handleImageRemove({ file, fileList }) {
+      this.linkImageList = fileList
+      this.formData.linkImage = fileList.length > 0 ? fileList.length : ''
+    },
+    uploadLinkImageSuccess({ response, file, fileList }) {
+      this.linkImageList = fileList
+      this.formData.linkImage = fileList.length > 0 ? fileList.length : ''
+    },
+    handleLinkImageRemove({ file, fileList }) {
+      this.linkImageList = fileList
+      this.formData.linkImage = fileList.length > 0 ? fileList.length : ''
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  display: flex;
+  justify-content: center;
+}
+.form-container {
+  display: inline-block;
+  padding: 80px 0;
+}
+.banner {
+  position: relative;
+  box-sizing: border-box;
+  border: 1px dashed #ddd;
+  cursor: pointer;
+  user-select: none;
+
+  .tip {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 20px;
+    color: #ddd;
+    white-space: nowrap;
+  }
+
+  img {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    z-index: 1;
+  }
+}
+</style>