InviteListDialog.vue 10.1 KB
<template>
  <el-dialog
    :visible.sync="visibleProxy"
    :show-close="false"
    width="90%"
    :close-on-click-modal="false"
    custom-class="invite-list-dialog"
    append-to-body
  >
    <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 class="dialog-search">
        <el-form @submit.native.prevent :inline="true" size="small">
          <el-form-item label="邀约时间">
            <el-date-picker v-model="query.yysj" type="daterange" value-format="timestamp" format="yyyy-MM-dd" start-placeholder="开始" end-placeholder="结束" style="width:220px" />
          </el-form-item>
          <el-form-item label="邀约客户">
            <el-select v-model="query.yykh" filterable remote reserve-keyword clearable placeholder="搜索客户" :remote-method="searchMember" :loading="memberLoading" style="width:200px">
              <el-option v-for="m in memberOptions" :key="m.value" :label="m.label" :value="m.value" />
            </el-select>
          </el-form-item>
          <template v-if="showAll">
            <el-form-item label="电话是否有效">
              <el-select v-model="query.dhsfyx" placeholder="请选择" clearable style="width:120px">
                <el-option label="是" value="是" /><el-option label="否" value="否" />
              </el-select>
            </el-form-item>
            <el-form-item label="联系时间">
              <el-date-picker v-model="query.lxsj" type="daterange" value-format="timestamp" format="yyyy-MM-dd" start-placeholder="开始" end-placeholder="结束" style="width:220px" />
            </el-form-item>
          </template>
          <el-form-item>
            <el-button type="primary" @click="search">查询</el-button>
            <el-button @click="reset">重置</el-button>
            <el-button type="text" @click="showAll = !showAll">
              {{ showAll ? '收起' : '展开' }}
              <i :class="showAll ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
            </el-button>
          </el-form-item>
        </el-form>
      </div>

      <div class="dialog-content">
        <el-table v-loading="loading" :data="list" border size="small" :header-cell-style="{ background:'#f5f7fa', color:'#606266', fontWeight:600 }">
          <el-table-column prop="storeName" label="门店" show-overflow-tooltip />
          <el-table-column prop="yyrName" label="邀约人" />
          <el-table-column label="邀约时间" width="140">
            <template slot-scope="{ row }">{{ formatDate(row.yysj) }}</template>
          </el-table-column>
          <el-table-column prop="yykhxm" label="邀约客户" />
          <el-table-column label="电话是否有效" width="120">
            <template slot-scope="{ row }">{{ row.dhsfyx || '-' }}</template>
          </el-table-column>
          <el-table-column prop="tkbh" label="关联拓客号" width="160" show-overflow-tooltip />
          <el-table-column label="联系时间" width="140">
            <template slot-scope="{ row }">{{ formatDate(row.lxsj) }}</template>
          </el-table-column>
          <el-table-column prop="lxjl" label="联系记录" show-overflow-tooltip />
        </el-table>
      </div>

      <div class="dialog-footer">
        <el-pagination
          background
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          :page-size.sync="listQuery.pageSize"
          :current-page.sync="listQuery.currentPage"
          :page-sizes="[10, 20, 50, 100]"
          @size-change="initData"
          @current-change="initData"
        />
      </div>
    </div>
  </el-dialog>
</template>

<script>
const MOCK_INVITE = [
  { id: '1', storeName: '金沙', yyrName: '何玲', yysj: '2026-02-11 21:45:11', yykhxm: '李芳', dhsfyx: '是', lxsj: '2026-02-11 21:45:19', lxjl: '已约', tkbh: '' },
  { id: '2', storeName: '金沙', yyrName: '何玲', yysj: '2026-02-11 21:44:34', yykhxm: '欧玉蓉', dhsfyx: '是', lxsj: '2026-02-11 21:44:39', lxjl: '已约', tkbh: '' },
  { id: '3', storeName: '金沙', yyrName: '何玲', yysj: '2026-02-11 21:43:57', yykhxm: '贺憨憨', dhsfyx: '是', lxsj: '2026-02-11 21:44:02', lxjl: '已约', tkbh: '' },
  { id: '4', storeName: '金沙', yyrName: '何玲', yysj: '2026-02-11 21:43:20', yykhxm: '王好', dhsfyx: '是', lxsj: '2026-02-11 21:43:24', lxjl: '已约', tkbh: '' },
  { id: '5', storeName: '南湖', yyrName: '郝莉娜', yysj: '2026-02-11 21:18:45', yykhxm: '林小芊', dhsfyx: '是', lxsj: '2026-02-11 21:18:52', lxjl: '1', tkbh: '' },
  { id: '6', storeName: '金沙', yyrName: '蒲艳婷', yysj: '2026-02-11 20:51:40', yykhxm: '李科', dhsfyx: '是', lxsj: '2026-02-11 20:51:44', lxjl: '已约', tkbh: '' },
  { id: '7', storeName: '金沙', yyrName: '蒲艳婷', yysj: '2026-02-11 20:51:03', yykhxm: '张亚琼', dhsfyx: '是', lxsj: '2026-02-11 20:51:07', lxjl: '已约', tkbh: '' },
  { id: '8', storeName: '金沙', yyrName: '蒲艳婷', yysj: '2026-02-11 20:50:18', yykhxm: '皮丹', dhsfyx: '是', lxsj: '2026-02-11 20:50:30', lxjl: '已约', tkbh: '' },
  { id: '9', storeName: '金沙', yyrName: '蒲艳婷', yysj: '2026-02-11 20:49:35', yykhxm: '何欢', dhsfyx: '是', lxsj: '2026-02-11 20:49:40', lxjl: '已约', tkbh: '' },
  { id: '10', storeName: '明信', yyrName: '冷忠翠', yysj: '2026-02-11 19:44:42', yykhxm: '赵玲艳', dhsfyx: '是', lxsj: '2026-02-11 19:44:52', lxjl: '下午5.30', tkbh: '' }
]

export default {
  name: 'InviteListDialog',
  props: { visible: { type: Boolean, default: false } },
  data() {
    return {
      showAll: false,
      loading: false,
      memberLoading: false,
      memberOptions: [],
      list: [],
      total: 0,
      mockData: MOCK_INVITE,
      query: { yysj: undefined, yykh: undefined, dhsfyx: undefined, lxsj: undefined },
      listQuery: { currentPage: 1, pageSize: 10, sort: 'desc', sidx: '' }
    }
  },
  computed: {
    visibleProxy: {
      get() { return this.visible },
      set(v) { this.$emit('update:visible', v) }
    }
  },
  watch: {
    visible(v) { if (v) { this.initData(); this.loadMembers() } }
  },
  methods: {
    formatDate(ts) {
      if (!ts) return '-'
      if (typeof ts === 'string' && ts.includes('-')) return ts.substring(0, 10)
      const d = new Date(typeof ts === 'number' ? ts : Number(ts))
      if (isNaN(d.getTime())) return '-'
      return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
    },
    loadMembers() {
      const map = new Map()
      this.mockData.forEach(r => { if (!map.has(r.yykhxm)) map.set(r.yykhxm, { value: r.id, label: r.yykhxm }) })
      this.memberOptions = [...map.values()]
    },
    searchMember(keyword) {
      if (!keyword) { this.loadMembers(); return }
      this.memberLoading = true
      setTimeout(() => {
        this.memberOptions = this.mockData
          .filter(r => r.yykhxm.includes(keyword))
          .map(r => ({ value: r.id, label: r.yykhxm }))
          .filter((v, i, a) => a.findIndex(t => t.label === v.label) === i)
        this.memberLoading = false
      }, 200)
    },
    initData() {
      this.loading = true
      setTimeout(() => {
        let filtered = [...this.mockData]
        if (this.query.yykh) {
          const selected = this.memberOptions.find(m => m.value === this.query.yykh)
          if (selected) filtered = filtered.filter(r => r.yykhxm === selected.label)
        }
        if (this.query.dhsfyx) filtered = filtered.filter(r => r.dhsfyx === this.query.dhsfyx)
        this.total = filtered.length
        const start = (this.listQuery.currentPage - 1) * this.listQuery.pageSize
        this.list = filtered.slice(start, start + this.listQuery.pageSize)
        this.loading = false
      }, 300)
    },
    search() { this.listQuery.currentPage = 1; this.initData() },
    reset() {
      for (const k in this.query) this.query[k] = undefined
      this.listQuery = { currentPage: 1, pageSize: 10, sort: 'desc', sidx: '' }
      this.initData()
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .invite-list-dialog { max-width: 1600px; margin-top: 3vh !important; border-radius: 20px; padding: 0; background: radial-gradient(circle at 0 0, rgba(255,255,255,0.96) 0, rgba(248,250,252,0.98) 40%, rgba(241,245,249,0.98) 100%); box-shadow: 0 24px 48px rgba(15,23,42,0.18), 0 0 0 1px rgba(255,255,255,0.9); backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px); }
::v-deep .el-dialog__header { display: none; }
::v-deep .el-dialog__body { padding: 0; }
.dialog-inner { display: flex; flex-direction: column; max-height: 92vh; }
.dialog-header { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; margin: 18px 22px 0; padding: 10px 14px; border-radius: 14px; background: rgba(219,234,254,0.96); }
.dialog-title { font-size: 17px; 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; transition: all 0.15s; &:hover { background: rgba(0,0,0,0.06); color: #0f172a; } }
.dialog-search { flex-shrink: 0; padding: 12px 22px 4px; }
.dialog-content { flex: 1; min-height: 0; overflow: auto; padding: 0 22px; }
.dialog-footer { flex-shrink: 0; display: flex; align-items: center; justify-content: flex-end; padding: 10px 22px 14px; border-top: 1px solid rgba(229,231,235,0.6); }
::v-deep .invite-list-dialog .el-input__inner { border-radius: 999px; height: 32px; line-height: 32px; border-color: #e5e7eb; background-color: #f9fafb; &:focus { border-color: #2563eb; box-shadow: 0 0 0 1px rgba(37,99,235,0.18); } }
::v-deep .invite-list-dialog .el-button--primary { border-radius: 999px; background: #2563eb; border-color: #2563eb; box-shadow: 0 4px 10px rgba(37,99,235,0.35); }
::v-deep .invite-list-dialog .el-button--default { border-radius: 999px; }
::v-deep .invite-list-dialog .el-form-item { margin-bottom: 8px; }
::v-deep .invite-list-dialog .el-form-item__label { white-space: nowrap; }
::v-deep .invite-list-dialog .el-range-editor.el-input__inner { border-radius: 999px; }
</style>