customer-edit-dialog.vue 9.88 KB
<template>
  <el-dialog :visible.sync="visibleProxy" :show-close="false" width="560px" :close-on-click-modal="false"
    custom-class="customer-edit-dialog" append-to-body @open="handleOpen">
    <div class="dialog-inner">
      <div class="dialog-header">
        <div class="dialog-title">编辑客户</div>
        <span class="dialog-close" @click="visibleProxy = false"><i class="el-icon-close"></i></span>
      </div>

      <div v-loading="loading" class="dialog-body">
        <el-form ref="form" :model="form" :rules="rules" label-width="96px" size="small">
          <el-form-item label="客户名称" prop="khmc">
            <el-input v-model="form.khmc" placeholder="请输入客户姓名" maxlength="50" />
          </el-form-item>
          <el-form-item label="手机号" prop="sjh">
            <el-input v-model="form.sjh" placeholder="请输入手机号" maxlength="11" />
          </el-form-item>
          <el-form-item label="性别">
            <el-select v-model="form.xb" placeholder="请选择" clearable style="width: 100%">
              <el-option label="男" value="男" />
              <el-option label="女" value="女" />
            </el-select>
          </el-form-item>
          <el-form-item label="客户类型" prop="khlx">
            <el-select v-model="form.khlx" placeholder="请选择客户类型" style="width: 100%">
              <el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="出生日期">
            <el-date-picker v-model="form.yanglsr" type="date" value-format="timestamp" placeholder="请选择出生日期"
              style="width: 100%" />
          </el-form-item>
          <el-form-item label="归属门店" prop="gsmd">
            <el-select v-model="form.gsmd" placeholder="请选择归属门店" filterable style="width: 100%"
              :disabled="storeOptions.length <= 1" @change="handleStoreChange">
              <el-option v-for="s in storeOptions" :key="s.id" :label="s.fullName" :value="s.id" />
            </el-select>
          </el-form-item>
          <el-form-item label="健康师">
            <el-select v-model="form.mainHealthUser" placeholder="请选择健康师" filterable clearable style="width: 100%"
              :loading="healthLoading">
              <el-option v-for="u in healthOptions" :key="u.value" :label="u.label" :value="u.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="负责顾问">
            <el-select v-model="form.subHealthUser" placeholder="请选择负责顾问" filterable clearable style="width: 100%"
              :loading="advisorLoading">
              <el-option v-for="u in advisorOptions" :key="u.value" :label="u.label" :value="u.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="联系地址">
            <el-input v-model="form.lxdz" placeholder="请输入联系地址" maxlength="200" />
          </el-form-item>
          <el-form-item label="备注">
            <el-input v-model="form.bz" type="textarea" :rows="3" placeholder="请输入备注" maxlength="500" show-word-limit />
          </el-form-item>
          <el-form-item label="自定义标签">
            <member-custom-tags-editor :member-id="form.id" v-model="customTags" />
          </el-form-item>
        </el-form>
      </div>

      <div class="dialog-footer">
        <el-button size="small" @click="visibleProxy = false">取消</el-button>
        <el-button type="primary" size="small" :loading="submitting" @click="handleSubmit">保存</el-button>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import { getKhxxInfo, updateKhxx } from '@/api/lqKhxx'
import { getStoreUserList } from '@/api/storeUser'
import MemberCustomTagsEditor from '@/components/member-custom-tags-editor.vue'

export default {
  name: 'CustomerEditDialog',
  components: { MemberCustomTagsEditor },
  props: {
    visible: { type: Boolean, default: false },
    memberId: { type: String, default: '' },
    typeOptions: { type: Array, default: () => [] },
    storeList: { type: Array, default: () => [] },
    currentStoreId: { type: String, default: '' }
  },
  data() {
    const validatePhone = (rule, value, callback) => {
      if (!value) {
        callback(new Error('请输入手机号'))
        return
      }
      if (!/^1[3-9]\d{9}$/.test(value)) {
        callback(new Error('请输入正确的手机号'))
        return
      }
      callback()
    }
    return {
      loading: false,
      submitting: false,
      healthLoading: false,
      advisorLoading: false,
      healthOptions: [],
      advisorOptions: [],
      customTags: [],
      form: {
        id: '',
        khmc: '',
        sjh: '',
        xb: '',
        khlx: '',
        yanglsr: null,
        gsmd: '',
        mainHealthUser: '',
        subHealthUser: '',
        lxdz: '',
        bz: ''
      },
      rules: {
        khmc: [{ required: true, message: '请输入客户名称', trigger: 'blur' }],
        sjh: [{ required: true, validator: validatePhone, trigger: 'blur' }],
        khlx: [{ required: true, message: '请选择客户类型', trigger: 'change' }],
        gsmd: [{ required: true, message: '请选择归属门店', trigger: 'change' }]
      }
    }
  },
  computed: {
    visibleProxy: {
      get() { return this.visible },
      set(v) { this.$emit('update:visible', v) }
    },
    storeOptions() {
      if (this.storeList && this.storeList.length) {
        return this.storeList.map(s => ({
          id: s.id,
          fullName: s.fullName || s.storeName || s.name || s.id
        }))
      }
      if (this.currentStoreId) {
        const name = (this.$store.getters.storeInfo || {}).storeName || '当前门店'
        return [{ id: this.currentStoreId, fullName: name }]
      }
      return []
    }
  },
  methods: {
    async handleOpen() {
      if (!this.memberId) return
      this.loading = true
      try {
        const res = await getKhxxInfo(this.memberId)
        const data = res.data || {}
        this.form = {
          id: data.id || this.memberId,
          khmc: data.khmc || '',
          sjh: data.sjh || '',
          xb: data.xb || '',
          khlx: data.khlx != null ? String(data.khlx) : '',
          yanglsr: data.yanglsr ? new Date(data.yanglsr).getTime() : null,
          gsmd: data.gsmd || this.currentStoreId || '',
          mainHealthUser: data.mainHealthUser || '',
          subHealthUser: data.subHealthUser || '',
          lxdz: data.lxdz || '',
          bz: data.bz || ''
        }
        this.customTags = Array.isArray(data.customTags) ? data.customTags : []
        await this.loadStaffOptions(this.form.gsmd)
        this.$nextTick(() => {
          if (this.$refs.form) this.$refs.form.clearValidate()
        })
      } catch (e) {
        this.$message.error('加载客户信息失败')
        this.visibleProxy = false
      } finally {
        this.loading = false
      }
    },
    async handleStoreChange(storeId) {
      this.form.mainHealthUser = ''
      this.form.subHealthUser = ''
      await this.loadStaffOptions(storeId)
    },
    async loadStaffOptions(storeId) {
      if (!storeId) {
        this.healthOptions = []
        this.advisorOptions = []
        return
      }
      this.healthLoading = true
      this.advisorLoading = true
      try {
        const [healthRes, advisorRes] = await Promise.all([
          getStoreUserList({ mdid: storeId, gw: '健康师', currentPage: 1, pageSize: 500 }),
          getStoreUserList({ mdid: storeId, gw: '健康师', currentPage: 1, pageSize: 500 })
        ])
        const mapUser = (list) => (list || []).map(u => ({
          value: u.id,
          label: u.realName || u.account || u.id
        }))
        this.healthOptions = mapUser(healthRes.data?.list)
        this.advisorOptions = mapUser(advisorRes.data?.list)
      } catch (e) {
        this.healthOptions = []
        this.advisorOptions = []
      } finally {
        this.healthLoading = false
        this.advisorLoading = false
      }
    },
    handleSubmit() {
      this.$refs.form.validate(async valid => {
        if (!valid) return
        this.submitting = true
        try {
          const payload = {
            id: this.form.id,
            khmc: this.form.khmc,
            sjh: this.form.sjh,
            xb: this.form.xb || null,
            khlx: this.form.khlx,
            gsmd: this.form.gsmd,
            mainHealthUser: this.form.mainHealthUser || null,
            subHealthUser: this.form.subHealthUser || null,
            lxdz: this.form.lxdz || null,
            bz: this.form.bz || null,
            yanglsr: this.form.yanglsr || null
          }
          await updateKhxx(this.form.id, payload)
          this.$message.success('客户信息已更新')
          this.$emit('success')
          this.visibleProxy = false
        } catch (e) {
          // 错误由拦截器处理
        } finally {
          this.submitting = false
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .customer-edit-dialog {
  border-radius: 16px;
  padding: 0;

  .el-dialog__header {
    display: none;
  }

  .el-dialog__body {
    padding: 0;
  }
}

.dialog-inner {
  display: flex;
  flex-direction: column;
}

.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px 12px;
  border-bottom: 1px solid #f1f5f9;
}

.dialog-title {
  font-size: 16px;
  font-weight: 600;
  color: #0f172a;
}

.dialog-close {
  cursor: pointer;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: #64748b;

  &:hover {
    background: rgba(0, 0, 0, 0.06);
    color: #0f172a;
  }
}

.dialog-body {
  padding: 16px 20px 8px;
  max-height: 65vh;
  overflow: auto;
}

.dialog-footer {
  display: flex;
  justify-content: flex-start;
  gap: 8px;
  padding: 12px 20px 16px;
  border-top: 1px solid #f1f5f9;
}
</style>