|
|
<template>
|
|
|
<div class="member-card-create">
|
|
|
<!-- 顶部标题和统计 -->
|
|
|
<div class="page-header">
|
|
|
<h2>办理会员卡</h2>
|
|
|
<div class="statistics">
|
|
|
<el-tag type="success">今日办理:{{ todayCount }} 张</el-tag>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div>
|
|
|
|
|
|
</div>
|
|
|
<el-card shadow="never" class="main-card">
|
|
|
<!-- 步骤条 -->
|
|
|
<el-steps :active="activeStep" finish-status="success" class="steps">
|
|
|
<el-step title="选择会员" description="选择或创建会员"></el-step>
|
|
|
<el-step title="选择卡类型" description="选择会员卡类型"></el-step>
|
|
|
<el-step title="填写信息" description="填写办理信息"></el-step>
|
|
|
</el-steps>
|
|
|
|
|
|
<!-- 步骤1:选择会员 -->
|
|
|
<div v-if="activeStep === 0" class="step-content">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span=12>
|
|
|
<div class="section-title">
|
|
|
<h3>搜索会员</h3>
|
|
|
<el-button type="primary" size="small" @click="handleAddStudent">
|
|
|
创建新会员
|
|
|
</el-button>
|
|
|
</div>
|
|
|
|
|
|
<el-input
|
|
|
v-model="searchKeyword"
|
|
|
placeholder="请输入会员手机号"
|
|
|
clearable
|
|
|
@keyup.enter="searchMember"
|
|
|
class="search-input"
|
|
|
>
|
|
|
<el-button slot="append" icon="el-icon-search" @click="searchMember"></el-button>
|
|
|
</el-input>
|
|
|
|
|
|
<div v-if="memberList.length > 0" class="member-list">
|
|
|
<el-radio-group v-model="selectedMemberId" @change="handleMemberSelect">
|
|
|
<div v-for="member in memberList" :key="member.studentId" class="member-item">
|
|
|
<el-radio :label="member.studentId" class="member-radio">
|
|
|
<div class="member-info">
|
|
|
<div class="member-name">{{ member.studentName }}</div>
|
|
|
<div class="member-phone">{{ member.phone }}</div>
|
|
|
<div class="member-phone">{{ member.age }}岁</div>
|
|
|
<div class="member-tags">
|
|
|
{{sexFormat(member)}}
|
|
|
<el-tag size="mini" type="info">生日{{ member.birthDay || '未设置生日' }}</el-tag>
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-radio>
|
|
|
</div>
|
|
|
</el-radio-group>
|
|
|
</div>
|
|
|
<div v-else-if="searched" class="empty-state">
|
|
|
<el-empty description="未找到相关会员"></el-empty>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span=12>
|
|
|
<div class="selected-member" v-if="selectedMember">
|
|
|
<div class="section-title">
|
|
|
<h3>已选会员信息</h3>
|
|
|
</div>
|
|
|
|
|
|
<el-descriptions :column="1" border>
|
|
|
<el-descriptions-item label="会员编号">{{ selectedMember.studentId || '-' }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="姓名">{{ selectedMember.studentName }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="手机号">{{ selectedMember.phone }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="性别">
|
|
|
{{sexFormat(selectedMember)}}
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="生日">{{ selectedMember.birthDay || '-' }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="注册时间">{{ selectedMember.inTime || '-' }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
<div v-if="memberCards.length > 0" class="current-cards">
|
|
|
<h4>名下会员卡</h4>
|
|
|
<el-table :data="memberCards" size="small">
|
|
|
<el-table-column prop="cardNo" label="卡号"></el-table-column>
|
|
|
<el-table-column prop="cardTypeName" label="类型"></el-table-column>
|
|
|
<el-table-column prop="chargeType" label="扣费方式">
|
|
|
<template slot-scope="scope">
|
|
|
{{ scope.row.chargeType=='count'?'按次数':scope.row.chargeType=='total_fee'?'按储值':'按周期' }}
|
|
|
{{scope.row.chargeType=='count'?'(余 '+scope.row.remainingCount+' 次)':''}}
|
|
|
{{scope.row.chargeType=='total_fee'?'(余 '+scope.row.remainingTotalFee+' ¥)':''}}
|
|
|
{{scope.row.chargeType=='days'?'(余 '+scope.row.remainingDays+' 天)':''}}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="status" label="状态">
|
|
|
<template slot-scope="scope">
|
|
|
<el-tag :type="getStatusTagType(scope.row.status)" size="mini">
|
|
|
{{ scope.row.statusDesc }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="expiryDate" label="到期时间"></el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
<div v-else class="placeholder">
|
|
|
<el-empty description="请选择会员"></el-empty>
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
|
|
|
<div class="step-actions">
|
|
|
<el-button type="primary" :disabled="!selectedMemberId" @click="nextStep">
|
|
|
下一步:选择卡类型
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 步骤2:选择卡类型 -->
|
|
|
<div v-if="activeStep === 1" class="step-content">
|
|
|
<member-card-Type-table ref="memberCardtype" />
|
|
|
<div class="step-actions">
|
|
|
<el-button @click="prevStep">上一步</el-button>
|
|
|
<el-button
|
|
|
type="primary"
|
|
|
@click="nextStepFor2"
|
|
|
>
|
|
|
下一步:填写信息
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 步骤3:填写信息 -->
|
|
|
<div v-if="activeStep === 2" class="step-content">
|
|
|
<el-form ref="form" :model="formData" :rules="formRules" label-width="120px">
|
|
|
<el-row :gutter="10" style="background-color: #e7e9ea;">
|
|
|
<el-col span="12">
|
|
|
<el-form-item label="会员信息">
|
|
|
<div class="member-info-display">
|
|
|
<div style="font-weight: bold;font-size: 16px">{{ selectedMember.studentName }}</div>
|
|
|
<div class="sub-info">{{ selectedMember.phone }}</div>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col span="12" >
|
|
|
<el-form-item label="卡类名称">
|
|
|
|
|
|
<div v-if="chargeType=='days'" class="card-type-display" >
|
|
|
<div style="color: #00afff;font-weight: bold;font-size: 16px">{{selectedCardType.cardName }}</div>
|
|
|
<div class="sub-info" >会员卡扣费方式 :按周期</div>
|
|
|
<div class="sub-info" >总天数/有效期 :{{ selectedCardType.days }}天</div>
|
|
|
<div class="sub-info" v-if="selectedCardType.days">
|
|
|
根据卡类型,默认有效期为 {{ selectedCardType.days }} 天</div>
|
|
|
</div>
|
|
|
|
|
|
<div v-if="chargeType=='count'" class="card-type-display">
|
|
|
<div style="color: #00afff;font-weight: bold;font-size: 16px">{{selectedCardType.cardName }}</div>
|
|
|
<div class="sub-info" >会员卡扣费方式 :按次数</div>
|
|
|
<div class="sub-info" >默认课程总次数 :{{ selectedCardType.count }}次</div>
|
|
|
<div class="sub-info" v-if="selectedCardType.days">
|
|
|
根据卡类型,默认有效期为 {{ selectedCardType.days }} 天</div>
|
|
|
</div>
|
|
|
|
|
|
<div v-if="chargeType=='total_fee'" class="card-type-display">
|
|
|
<div style="color: #00afff;font-weight: bold;font-size: 16px">{{ selectedCardType.cardName }}</div>
|
|
|
<div class="sub-info" >会员卡扣费方式 :按储值</div>
|
|
|
<div class="sub-info" >默认储值金额:{{ selectedCardType.totalFee }} ¥</div>
|
|
|
<div class="sub-info" v-if="selectedCardType.days">
|
|
|
根据卡类型,默认有效期为 {{ selectedCardType.days }} 天</div>
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
<el-row :gutter="20" style="margin-top: 10px">
|
|
|
<el-col :span=12>
|
|
|
|
|
|
|
|
|
<el-form-item label="经办校区" prop="handleDepartId">
|
|
|
<el-select
|
|
|
v-model="formData.handleDepartId"
|
|
|
placeholder="请选择经办校区"
|
|
|
clearable
|
|
|
size="small"
|
|
|
filterable
|
|
|
default-first-option
|
|
|
>
|
|
|
<el-option
|
|
|
v-for="item in campusOptions"
|
|
|
:key="item.id"
|
|
|
:label="item.label"
|
|
|
:value="item.id"
|
|
|
/>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="销售员工" prop="saleStaffId">
|
|
|
<user-select v-model="formData.saleStaffId" style="width: 180px" />
|
|
|
</el-form-item >
|
|
|
<el-form-item label="佣金方案" prop="commissionPlansId">
|
|
|
<commission-select v-model="formData.commissionPlansId" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="收款账户" prop="accountId">
|
|
|
<el-select
|
|
|
v-model="formData.accountId"
|
|
|
placeholder="请选择收款账户"
|
|
|
clearable
|
|
|
size="small"
|
|
|
filterable
|
|
|
default-first-option
|
|
|
>
|
|
|
<el-option
|
|
|
v-for="item in receiptAccountOptions"
|
|
|
:key="item.accountId"
|
|
|
:label="item.accountName"
|
|
|
:value="item.accountId"
|
|
|
/>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span=12>
|
|
|
|
|
|
<el-form-item label="实付金额" prop="price">
|
|
|
<el-input-number
|
|
|
v-model="formData.price"
|
|
|
:min="0"
|
|
|
:step="100"
|
|
|
:precision="2"
|
|
|
placeholder="请输入购买价格"
|
|
|
></el-input-number>
|
|
|
元
|
|
|
</el-form-item>
|
|
|
|
|
|
<div v-if="chargeType=='days'">
|
|
|
<el-form-item label="开卡日期:" prop="haveActivationDate" class="align-left">
|
|
|
<el-radio-group v-model="formData.haveActivationDate" @change="changeHaveActivationDate" >
|
|
|
<el-radio label="1">立即开卡</el-radio>
|
|
|
<el-radio label="2">首次预约开卡</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="激活日期" v-if="formData.haveActivationDate=='1'" prop="activationDate">
|
|
|
<el-date-picker
|
|
|
v-model="formData.activationDate"
|
|
|
type="date"
|
|
|
placeholder="选择激活日期"
|
|
|
value-format="yyyy-MM-dd"
|
|
|
:picker-options="activationDateOptions"
|
|
|
@change="calculateExpiryDate"
|
|
|
>
|
|
|
</el-date-picker>
|
|
|
|
|
|
</el-form-item>
|
|
|
<el-form-item label="到期日期" v-if="formData.haveActivationDate=='1'" prop="expiryDate">
|
|
|
<el-date-picker
|
|
|
v-model="formData.expiryDate"
|
|
|
type="date"
|
|
|
placeholder="选择到期日期"
|
|
|
value-format="yyyy-MM-dd"
|
|
|
:picker-options="expiryDateOptions"
|
|
|
@change="calculateDays"
|
|
|
>
|
|
|
</el-date-picker>
|
|
|
<span class="form-tip" > 共{{ formData.totalDays }}天,截止至当天23:59:59;</span>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="储值天数" v-if="formData.haveActivationDate=='2'" prop="totalDays" >
|
|
|
<el-input-number
|
|
|
v-model="formData.totalDays"
|
|
|
:min="0"
|
|
|
:step="100"
|
|
|
:precision="0"
|
|
|
placeholder="请输入储值天数"
|
|
|
>
|
|
|
</el-input-number>
|
|
|
天
|
|
|
<span class="form-tip" > * 该卡从会员首次约课时算第一天,再往后共{{ formData.totalDays }}天</span>
|
|
|
</el-form-item>
|
|
|
</div >
|
|
|
<div v-else>
|
|
|
<el-form-item label="卡有效期:" prop="haveExpiryDate" class="align-left">
|
|
|
<el-radio-group v-model="formData.haveExpiryDate" @change="changeHaveExpiryDate">
|
|
|
<el-radio label="1">不限期,用完失效</el-radio>
|
|
|
<el-radio label="2">设置有效期</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="到期日期" v-if="formData.haveExpiryDate=='2'" prop="expiryDate">
|
|
|
<el-date-picker
|
|
|
v-model="formData.expiryDate"
|
|
|
type="date"
|
|
|
placeholder="选择到期日期"
|
|
|
value-format="yyyy-MM-dd"
|
|
|
:picker-options="expiryDateOptions"
|
|
|
>
|
|
|
</el-date-picker>
|
|
|
<span class="form-tip" > 截止至当天23:59:59;</span>
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
<el-form-item v-if="chargeType=='total_fee'" label="储值金额" prop="totalFee">
|
|
|
<el-input-number
|
|
|
v-model="formData.totalFee"
|
|
|
:min="0"
|
|
|
:step="100"
|
|
|
:precision="2"
|
|
|
placeholder="请输入购买价格"
|
|
|
>
|
|
|
</el-input-number>
|
|
|
元
|
|
|
<span class="form-tip"> * 举例:若实付金额1000,送200,则储值金额应填写1200</span>
|
|
|
</el-form-item>
|
|
|
<el-form-item v-if="chargeType=='count'" label="充值课时" prop="totalCount">
|
|
|
<el-input-number
|
|
|
v-model="formData.totalCount"
|
|
|
:min="0"
|
|
|
:step="1"
|
|
|
:precision="1"
|
|
|
placeholder="请输入充值次数"
|
|
|
>
|
|
|
</el-input-number>
|
|
|
次
|
|
|
</el-form-item>
|
|
|
<el-form-item label="备注" prop="notes">
|
|
|
<el-input
|
|
|
v-model="formData.notes"
|
|
|
type="textarea"
|
|
|
:rows="3"
|
|
|
placeholder="请输入备注信息"
|
|
|
></el-input>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</el-form>
|
|
|
|
|
|
<div class="summary-card">
|
|
|
<h3>办理信息汇总</h3>
|
|
|
<el-descriptions :column="2" border>
|
|
|
<el-descriptions-item label="会员">{{ selectedMember.studentName }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="手机号">{{ selectedMember.phone }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="卡类名称">{{ selectedCardType.cardName }}</el-descriptions-item>
|
|
|
<el-descriptions-item v-if="chargeType=='total_fee'" label="储值金额">{{ formData.totalFee }} ¥</el-descriptions-item>
|
|
|
<el-descriptions-item v-if="chargeType=='count'" label="充值课时">{{ formData.totalCount }} 次</el-descriptions-item>
|
|
|
<el-descriptions-item v-if="chargeType=='days'" label="有效天数">{{ formData.totalDays }} 天</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="实付金额">{{ formData.price }} ¥</el-descriptions-item>
|
|
|
<el-descriptions-item label="收款账户">
|
|
|
{{ getPaymentMethodName(formData.accountId) }}
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="激活日期">
|
|
|
{{ formData.activationDate || '暂不激活' }}
|
|
|
</el-descriptions-item>
|
|
|
<el-descriptions-item label="到期日期">
|
|
|
{{ formData.expiryDate }}
|
|
|
</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
</div>
|
|
|
|
|
|
<div class="step-actions">
|
|
|
<el-button @click="prevStep">上一步</el-button>
|
|
|
<el-button
|
|
|
type="primary"
|
|
|
@click="validateAndNext"
|
|
|
:loading="validating"
|
|
|
>
|
|
|
确认办理
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
</el-card>
|
|
|
<change-student ref="changeStudent" @success="handleMemberSelect" />
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import {select as cardTypeSelect} from '@/api/school/sc/memberCardType/index'
|
|
|
import {listStudent} from '@/api/school/sc/student/index'
|
|
|
import { select as receiptSelect} from '@/api/school/system/receipt'
|
|
|
import {selectDictLabel} from "@/utils/commonUtils";
|
|
|
import { campusList } from '@/api/school/system/dept'
|
|
|
import memberCardTypeTable from '@/components/sc/memberCardTypes/memberCardTypeTable.vue'
|
|
|
import changeStudent from '@/components/sc/student/changeStudent'
|
|
|
import memberCardApi from '@/api/school/sc/memberCard/index'
|
|
|
import commissionSelect from '@/components/sc/commission/commissionSelect'
|
|
|
import userSelect from '@/components/system/user/userSelect'
|
|
|
export default {
|
|
|
name: 'MemberCardCreate',
|
|
|
components: {
|
|
|
memberCardTypeTable,
|
|
|
changeStudent,
|
|
|
commissionSelect,
|
|
|
userSelect
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
activeStep: 0,
|
|
|
|
|
|
// 统计信息
|
|
|
todayCount: 0,
|
|
|
monthCount: 0,
|
|
|
|
|
|
// 会员相关
|
|
|
searchKeyword: '',
|
|
|
memberList: [],
|
|
|
selectedMemberId: null,
|
|
|
selectedMember: null,
|
|
|
memberCards: [],
|
|
|
searched: false,
|
|
|
sexOptions:[],
|
|
|
|
|
|
// 卡类型相关
|
|
|
cardTypes: [],
|
|
|
selectedCardTypeId: null,
|
|
|
selectedCardType: null,
|
|
|
chargeType: null,
|
|
|
|
|
|
// 经办校区
|
|
|
campusOptions: [],
|
|
|
|
|
|
// 表单数据
|
|
|
formData: {
|
|
|
handleDepartId:'',
|
|
|
saleStaffId:'',
|
|
|
commissionPlansId:'',
|
|
|
accountId: '',//收款账户
|
|
|
haveActivationDate:'1',//时间卡 是否激活
|
|
|
haveExpiryDate:'1',//储值or次数卡 是否设置有效期
|
|
|
activationDate: '',//激活时间
|
|
|
expiryDate: '',//过期时间
|
|
|
price: 0,
|
|
|
totalFee: 0,
|
|
|
totalCount: 0,
|
|
|
totalDays: 0,
|
|
|
notes: '',
|
|
|
orderId:''
|
|
|
},
|
|
|
autoGenerateCardNo: true,
|
|
|
|
|
|
// 支付相关
|
|
|
receiptAccountOptions:[],
|
|
|
paymentType: 'WECHAT',
|
|
|
paying: false,
|
|
|
saving: false,
|
|
|
validating: false,
|
|
|
|
|
|
// 对话框控制
|
|
|
showCreateMemberDialog: false,
|
|
|
showCardTypeDetailDialog: false,
|
|
|
|
|
|
// 表单验证规则
|
|
|
formRules: {
|
|
|
accountId: [
|
|
|
{ required: true, message: '请选择收款账户', trigger: 'change' }
|
|
|
],
|
|
|
handleDepartId: [
|
|
|
{ required: true, message: '请选择经办校区', trigger: 'change' }
|
|
|
],
|
|
|
saleStaffId: [
|
|
|
{ required: true, message: '请选择销售员工', trigger: 'change' }
|
|
|
],
|
|
|
commissionPlansId: [
|
|
|
{ required: true, message: '请选择佣金方案', trigger: 'change' }
|
|
|
],
|
|
|
price: [
|
|
|
{ required: true, message: '请输入购买价格', trigger: 'blur' },
|
|
|
{ type: 'number', min: 0, message: '价格不能小于0', trigger: 'blur' }
|
|
|
],
|
|
|
activationDate: [
|
|
|
{ validator: (rule, value, callback) => {
|
|
|
// 如果 haveActivationDate 为 1,activationDate 不能为空
|
|
|
if (this.formData.haveActivationDate === '1' && !value) {
|
|
|
callback(new Error('请选择激活日期'));
|
|
|
} else {
|
|
|
callback(); // 验证通过
|
|
|
}
|
|
|
},
|
|
|
trigger: 'change' // 日期选择器用 change 触发
|
|
|
},
|
|
|
],
|
|
|
expiryDate: [
|
|
|
{ validator: (rule, value, callback) => {
|
|
|
// 条件1:haveActivationDate 为 1 时,有效期不能为空
|
|
|
// 条件2:haveExpiryDate 为 2 时,有效期不能为空
|
|
|
const needExpiryDate = this.formData.haveActivationDate === '1' || this.formData.haveExpiryDate === '2';
|
|
|
if (needExpiryDate && !value) {
|
|
|
callback(new Error('请选择有效期'));
|
|
|
} else {
|
|
|
callback(); // 验证通过
|
|
|
}
|
|
|
},
|
|
|
trigger: 'blur'// 日期选择器用 change 触发
|
|
|
},
|
|
|
],
|
|
|
days: [
|
|
|
{
|
|
|
validator: (rule, value, callback) => {
|
|
|
// 如果 haveActivationDate 为 2,days 不能为空且不能为 0
|
|
|
if (this.formData.haveActivationDate === '2') {
|
|
|
if (!value || value === 0) {
|
|
|
callback(new Error('请输入有效天数'));
|
|
|
} else if (value < 0) {
|
|
|
callback(new Error('有效天数不能小于0'));
|
|
|
} else {
|
|
|
callback();
|
|
|
}
|
|
|
} else {
|
|
|
callback(); // 其他情况不验证
|
|
|
}
|
|
|
},
|
|
|
trigger: ['blur', 'change']// 输入框用 blur 触发
|
|
|
},
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
// 日期选择器选项
|
|
|
activationDateOptions: {
|
|
|
disabledDate(time) {
|
|
|
return time.getTime() < Date.now() - 8.64e7 // 不能选择过去的时间
|
|
|
}
|
|
|
},
|
|
|
expiryDateOptions: {
|
|
|
disabledDate(time) {
|
|
|
return time.getTime() < Date.now() - 8.64e7 // 不能选择过去的时间
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
this.loadCardTypes()
|
|
|
this.loadStatistics()
|
|
|
this.loadReceiptAccount()
|
|
|
this.getDictListByDictType('sys_user_sex').then(response => {
|
|
|
this.sexOptions = response.data
|
|
|
})
|
|
|
campusList().then(response => {
|
|
|
this.campusOptions = response.data
|
|
|
if (this.campusOptions.length === 1) {
|
|
|
this.formData.handleDepartId = this.campusOptions[0].id
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
methods: {
|
|
|
|
|
|
loadReceiptAccount(){
|
|
|
receiptSelect().then(response => {
|
|
|
this.receiptAccountOptions = response.data
|
|
|
})
|
|
|
},
|
|
|
// 加载统计信息
|
|
|
async loadStatistics() {
|
|
|
try {
|
|
|
memberCardApi.getTodayCardCount().then(response => {
|
|
|
this.todayCount = response.data || 0
|
|
|
})
|
|
|
} catch (error) {
|
|
|
console.error('加载统计信息失败:', error)
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 加载卡类型
|
|
|
async loadCardTypes() {
|
|
|
try {
|
|
|
cardTypeSelect({}).then(response => {
|
|
|
this.cardTypes = response.data || []
|
|
|
})
|
|
|
} catch (error) {
|
|
|
this.$message.error('加载卡类型失败')
|
|
|
console.error('加载卡类型失败:', error)
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 搜索会员
|
|
|
async searchMember() {
|
|
|
if (!this.searchKeyword.trim()) {
|
|
|
this.$message.warning('请输入搜索关键词')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
listStudent({phone:this.searchKeyword}).then(response => {
|
|
|
this.memberList = response.data.rows || []
|
|
|
this.searched = true
|
|
|
|
|
|
if (this.memberList.length === 0) {
|
|
|
this.$message.info('未找到相关会员')
|
|
|
}
|
|
|
})
|
|
|
} catch (error) {
|
|
|
this.$message.error('搜索会员失败')
|
|
|
console.error('搜索会员失败:', error)
|
|
|
}
|
|
|
},
|
|
|
// 性别字典翻译
|
|
|
sexFormat(row, column) {
|
|
|
return selectDictLabel(this.sexOptions, row.sex)
|
|
|
},
|
|
|
// 选择会员
|
|
|
async handleMemberSelect(studentId) {
|
|
|
const member = this.memberList.find(m => m.studentId === studentId)
|
|
|
if (member) {
|
|
|
this.selectedMember = member
|
|
|
await this.loadMemberCards(studentId)
|
|
|
}
|
|
|
},
|
|
|
// 加载会员的会员卡
|
|
|
async loadMemberCards(memberId) {
|
|
|
try {
|
|
|
const response = await memberCardApi.getMemberCards(memberId)
|
|
|
this.memberCards = response.data || []
|
|
|
} catch (error) {
|
|
|
console.error('加载会员卡失败:', error)
|
|
|
}
|
|
|
},
|
|
|
// 新建学员信息
|
|
|
handleAddStudent() {
|
|
|
this.$refs.changeStudent.handleAdd()
|
|
|
},
|
|
|
|
|
|
// 获取收款账户名称
|
|
|
getPaymentMethodName(method) {
|
|
|
let item=this.receiptAccountOptions.find(item => item.accountId == method);
|
|
|
let methodName=item==null?'':item.accountName;
|
|
|
return methodName;
|
|
|
},
|
|
|
|
|
|
// 获取状态标签类型
|
|
|
getStatusTagType(status) {
|
|
|
const typeMap = {
|
|
|
'ACTIVE': 'success',
|
|
|
'INACTIVE': 'info',
|
|
|
'EXPIRED': 'warning',
|
|
|
'SUSPENDED': 'danger',
|
|
|
'DEPLETED': 'danger'
|
|
|
}
|
|
|
return typeMap[status] || 'info'
|
|
|
},
|
|
|
|
|
|
changeHaveActivationDate(){
|
|
|
this.formData.activationDate=''
|
|
|
this.formData.expiryDate=''
|
|
|
this.formData.totalDays=0
|
|
|
|
|
|
},
|
|
|
changeHaveExpiryDate(){
|
|
|
if (this.formData.haveExpiryDate=='2'){
|
|
|
this.calculateExpiryDate()
|
|
|
return;
|
|
|
}
|
|
|
this.formData.expiryDate='' ;
|
|
|
},
|
|
|
// 计算到期日期
|
|
|
calculateExpiryDate( ) {
|
|
|
if (!this.selectedCardType || !this.selectedCardType.days) {
|
|
|
return '未设置'
|
|
|
}
|
|
|
const activationDate = this.formData.activationDate
|
|
|
? new Date(this.formData.activationDate)
|
|
|
: new Date()
|
|
|
const expiryDate = new Date(activationDate)
|
|
|
expiryDate.setDate(expiryDate.getDate() + this.selectedCardType.days)
|
|
|
this.formData.expiryDate=expiryDate.toISOString().split('T')[0];
|
|
|
this.calculateDays()
|
|
|
},
|
|
|
calculateDays(){
|
|
|
if (!this.formData.activationDate || !this.formData.expiryDate){
|
|
|
return;
|
|
|
}
|
|
|
const activationDate =new Date(this.formData.activationDate);
|
|
|
const expiryDate =new Date(this.formData.expiryDate);
|
|
|
const timeDiff = Math.abs(activationDate.getTime() - expiryDate.getTime());
|
|
|
const dayDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
|
|
|
this.formData.totalDays=dayDiff;
|
|
|
|
|
|
},
|
|
|
// 验证并进入下一步
|
|
|
async validateAndNext() {
|
|
|
this.$refs.form.validate(async (valid) => {
|
|
|
if (valid) {
|
|
|
this.validating = true
|
|
|
try {
|
|
|
// 这里可以添加一些业务验证
|
|
|
await this.handlePayment()
|
|
|
} catch (error) {
|
|
|
console.error('验证失败:', error)
|
|
|
} finally {
|
|
|
this.validating = false
|
|
|
}
|
|
|
} else {
|
|
|
this.$message.warning('请填写完整信息')
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
|
|
|
// 下一步
|
|
|
nextStep() {
|
|
|
if (this.activeStep < 2) {
|
|
|
this.activeStep++
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 上一步
|
|
|
prevStep() {
|
|
|
if (this.activeStep > 0) {
|
|
|
this.activeStep--
|
|
|
}
|
|
|
},
|
|
|
cleanForm(){
|
|
|
this.formData.haveActivationDate='1';
|
|
|
this.formData.haveExpiryDate='1';
|
|
|
this.formData.activationDate='';
|
|
|
this.formData.expiryDate='';
|
|
|
this.formData.price=0;
|
|
|
this.formData.totalFee=0;
|
|
|
this.formData.totalCount=0;
|
|
|
this.formData.totalDays=0;
|
|
|
|
|
|
},
|
|
|
nextStepFor2(){
|
|
|
if (this.$refs.memberCardtype.queryParams.cardType==undefined || this.$refs.memberCardtype.queryParams.cardType==''){
|
|
|
this.msgError('请选择收费模式!')
|
|
|
return ;
|
|
|
}
|
|
|
this.cleanForm()
|
|
|
this.formData.activationDate=new Date().toISOString().split('T')[0]
|
|
|
// if (this.$refs.memberCardtype.queryParams.cardType=='total_fee'){
|
|
|
// this.chargeType=this.$refs.memberCardtype.queryParams.cardType;
|
|
|
// this.selectedCardTypeId=this.$refs.memberCardtype.chooseCardTypeId[0];
|
|
|
// this.selectedCardType=this.$refs.memberCardtype.chooseCardTypes[0];
|
|
|
//
|
|
|
// if (this.selectedCardType ==null){
|
|
|
// this.selectedCardType={
|
|
|
// cardName:'储值卡',
|
|
|
// totalFee:0
|
|
|
// }
|
|
|
// }
|
|
|
// this.activeStep++
|
|
|
// return ;
|
|
|
// }
|
|
|
if (this.$refs.memberCardtype.chooseCardTypeId.length>1 || this.$refs.memberCardtype.chooseCardTypeId.length==0){
|
|
|
this.msgError('请选择1项,确认选择数量!')
|
|
|
return ;
|
|
|
}
|
|
|
this.chargeType=this.$refs.memberCardtype.queryParams.cardType;
|
|
|
this.selectedCardTypeId=this.$refs.memberCardtype.chooseCardTypeId[0];
|
|
|
this.selectedCardType=this.$refs.memberCardtype.chooseCardTypes[0];
|
|
|
this.calculateExpiryDate()
|
|
|
this.activeStep++
|
|
|
},
|
|
|
|
|
|
// 处理订单信息
|
|
|
async handlePayment() {
|
|
|
if (!this.selectedMemberId ) {
|
|
|
this.$message.error('请完成前面的步骤')
|
|
|
return
|
|
|
}
|
|
|
// if ( !this.selectedCardTypeId && this.chargeType!='total_fee') {
|
|
|
if ( !this.selectedCardTypeId) {
|
|
|
this.$message.error('请完成前面的步骤')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
this.paying = true
|
|
|
|
|
|
|
|
|
try {
|
|
|
// 构建办理会员卡的请求数据
|
|
|
const requestData = {
|
|
|
memberId: this.selectedMemberId,
|
|
|
cardTypeId: this.selectedCardTypeId,
|
|
|
|
|
|
handleDepartId:this.formData.handleDepartId,
|
|
|
saleStaffId:this.formData.saleStaffId,
|
|
|
commissionPlansId:this.formData.commissionPlansId,
|
|
|
|
|
|
haveActivationDate:this.formData.haveActivationDate,//时间卡 是否激活
|
|
|
haveExpiryDate:this.formData.haveExpiryDate,//储值or次数卡 是否设置有效期
|
|
|
activationDate: this.formData.activationDate || null,
|
|
|
expiryDate: this.formData.expiryDate || null,
|
|
|
|
|
|
price: this.formData.price,
|
|
|
accountId: this.formData.accountId,
|
|
|
orderNo: this.formData.orderNo,
|
|
|
|
|
|
totalFee: this.formData.totalFee || 0,
|
|
|
totalCount: this.formData.totalCount || 0,
|
|
|
totalDays: this.formData.totalDays || 0,
|
|
|
notes: this.formData.notes,
|
|
|
|
|
|
chargeType:this.chargeType
|
|
|
}
|
|
|
|
|
|
const response = await memberCardApi.createMemberCard(requestData)
|
|
|
|
|
|
if (response.respCode === '0000') {
|
|
|
this.$message.success('会员卡办理成功!')
|
|
|
|
|
|
// 重置表单
|
|
|
this.resetForm()
|
|
|
|
|
|
// 跳转到会员卡详情页
|
|
|
const cardId = response.data.id
|
|
|
// this.$router.push({
|
|
|
// name: 'MemberCardDetail',
|
|
|
// params: { id: cardId }
|
|
|
// })
|
|
|
} else {
|
|
|
this.$message.error(response.respMsg || '办理失败')
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('办理会员卡失败:', error)
|
|
|
this.$message.error('办理失败:' + (error.message || '网络错误'))
|
|
|
} finally {
|
|
|
this.paying = false
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 保存为草稿
|
|
|
async saveAsDraft() {
|
|
|
this.saving = true
|
|
|
try {
|
|
|
// TODO: 实现保存草稿功能
|
|
|
this.$message.success('已保存为草稿')
|
|
|
} catch (error) {
|
|
|
console.error('保存草稿失败:', error)
|
|
|
this.$message.error('保存草稿失败')
|
|
|
} finally {
|
|
|
this.saving = false
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 查看卡类型详情
|
|
|
showCardTypeDetail(cardType) {
|
|
|
this.selectedCardType = cardType
|
|
|
this.showCardTypeDetailDialog = true
|
|
|
},
|
|
|
|
|
|
|
|
|
// 处理会员创建成功
|
|
|
handleMemberCreateSuccess(newMember) {
|
|
|
this.showCreateMemberDialog = false
|
|
|
this.memberList.unshift(newMember)
|
|
|
this.selectedMemberId = newMember.id
|
|
|
this.selectedMember = newMember
|
|
|
this.searchKeyword = ''
|
|
|
this.$message.success('会员创建成功')
|
|
|
},
|
|
|
|
|
|
// 处理创建会员对话框关闭
|
|
|
handleCreateMemberClose() {
|
|
|
if (this.$refs.memberCreateForm) {
|
|
|
this.$refs.memberCreateForm.resetForm()
|
|
|
}
|
|
|
},
|
|
|
|
|
|
// 重置表单
|
|
|
resetForm() {
|
|
|
this.activeStep = 0
|
|
|
this.selectedMemberId = null
|
|
|
this.selectedMember = null
|
|
|
this.memberCards = []
|
|
|
this.selectedCardTypeId = null
|
|
|
this.selectedCardType = null
|
|
|
this.formData = {
|
|
|
handleDepartId:'',
|
|
|
saleStaffId:'',
|
|
|
commissionPlansId:'',
|
|
|
accountId: '',//收款账户
|
|
|
haveActivationDate:'1',//时间卡 是否激活
|
|
|
haveExpiryDate:'1',//储值or次数卡 是否设置有效期
|
|
|
activationDate: '',//激活时间
|
|
|
expiryDate: '',//过期时间
|
|
|
price: 0,
|
|
|
totalFee: 0,
|
|
|
totalCount: 0,
|
|
|
totalDays: 0,
|
|
|
notes: '',
|
|
|
orderNo: ''
|
|
|
}
|
|
|
this.autoGenerateCardNo = true
|
|
|
this.paymentType = 'WECHAT'
|
|
|
|
|
|
if (this.$refs.form) {
|
|
|
this.$refs.form.resetFields()
|
|
|
}
|
|
|
|
|
|
// 重新加载卡类型
|
|
|
this.loadCardTypes()
|
|
|
this.loadStatistics()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
.member-card-create {
|
|
|
padding: 20px;
|
|
|
|
|
|
.page-header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
h2 {
|
|
|
margin: 0;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.statistics {
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.main-card {
|
|
|
margin-top: 20px;
|
|
|
|
|
|
.steps {
|
|
|
margin-bottom: 40px;
|
|
|
}
|
|
|
|
|
|
.step-content {
|
|
|
padding: 20px;
|
|
|
|
|
|
.section-title {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
h3 {
|
|
|
margin: 0;
|
|
|
color: #333;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.search-input {
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
|
|
|
.member-list {
|
|
|
max-height: 400px;
|
|
|
overflow-y: auto;
|
|
|
|
|
|
.member-item {
|
|
|
padding: 10px;
|
|
|
margin-bottom: 10px;
|
|
|
border: 1px solid #ebeef5;
|
|
|
border-radius: 4px;
|
|
|
transition: all 0.3s;
|
|
|
|
|
|
&:hover {
|
|
|
border-color: #409eff;
|
|
|
background-color: #f5f7fa;
|
|
|
}
|
|
|
|
|
|
.member-radio {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.member-info {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
margin-left: 10px;
|
|
|
|
|
|
.member-name {
|
|
|
font-weight: bold;
|
|
|
font-size: 14px;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.member-phone {
|
|
|
font-size: 12px;
|
|
|
color: #666;
|
|
|
margin: 4px 0;
|
|
|
}
|
|
|
|
|
|
.member-tags {
|
|
|
display: flex;
|
|
|
gap: 5px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.empty-state {
|
|
|
text-align: center;
|
|
|
padding: 40px 0;
|
|
|
}
|
|
|
|
|
|
.selected-member {
|
|
|
.current-cards {
|
|
|
margin-top: 20px;
|
|
|
|
|
|
h4 {
|
|
|
margin: 20px 0 10px;
|
|
|
color: #333;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.placeholder {
|
|
|
text-align: center;
|
|
|
padding: 40px 0;
|
|
|
color: #999;
|
|
|
}
|
|
|
|
|
|
.card-type-list {
|
|
|
.card-type-item {
|
|
|
border: 2px solid #ebeef5;
|
|
|
border-radius: 8px;
|
|
|
padding: 20px;
|
|
|
margin-bottom: 20px;
|
|
|
cursor: pointer;
|
|
|
transition: all 0.3s;
|
|
|
height: 100%;
|
|
|
|
|
|
&:hover {
|
|
|
border-color: #409eff;
|
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
&.selected {
|
|
|
border-color: #67c23a;
|
|
|
background-color: #f0f9eb;
|
|
|
}
|
|
|
|
|
|
.card-type-header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
h3 {
|
|
|
margin: 0;
|
|
|
color: #333;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.card-type-price {
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
.price {
|
|
|
font-size: 24px;
|
|
|
font-weight: bold;
|
|
|
color: #f56c6c;
|
|
|
}
|
|
|
|
|
|
.original-price {
|
|
|
font-size: 14px;
|
|
|
color: #999;
|
|
|
text-decoration: line-through;
|
|
|
margin-left: 10px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.card-type-details {
|
|
|
margin-bottom: 15px;
|
|
|
|
|
|
.detail-item {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
margin-bottom: 8px;
|
|
|
font-size: 13px;
|
|
|
color: #666;
|
|
|
|
|
|
i {
|
|
|
margin-right: 8px;
|
|
|
color: #409eff;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.card-type-benefits {
|
|
|
h4 {
|
|
|
margin: 0 0 8px;
|
|
|
font-size: 14px;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
p {
|
|
|
margin: 0;
|
|
|
font-size: 13px;
|
|
|
color: #666;
|
|
|
line-height: 1.5;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.card-type-footer {
|
|
|
margin-top: 15px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.selected-card-type {
|
|
|
margin: 20px 0;
|
|
|
|
|
|
.selected-alert {
|
|
|
.selected-info {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
|
|
|
.price {
|
|
|
font-weight: bold;
|
|
|
color: #f56c6c;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.member-info-display,
|
|
|
.card-type-display {
|
|
|
padding: 8px 0;
|
|
|
|
|
|
.sub-info {
|
|
|
font-size: 12px;
|
|
|
color: #666;
|
|
|
margin-top: 4px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.form-tip {
|
|
|
font-size: 12px;
|
|
|
color: #999;
|
|
|
margin-top: 4px;
|
|
|
}
|
|
|
|
|
|
.summary-card {
|
|
|
margin-top: 30px;
|
|
|
padding: 20px;
|
|
|
background-color: #f5f7fa;
|
|
|
border-radius: 4px;
|
|
|
|
|
|
h3 {
|
|
|
margin: 0 0 15px;
|
|
|
color: #333;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.payment-options {
|
|
|
margin: 30px 0;
|
|
|
|
|
|
h3 {
|
|
|
margin: 0 0 15px;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
.payment-buttons {
|
|
|
display: flex;
|
|
|
gap: 10px;
|
|
|
|
|
|
.icon-wechat,
|
|
|
.icon-alipay {
|
|
|
margin-right: 5px;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.step-actions {
|
|
|
margin-top: 30px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.final-actions {
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
gap: 20px;
|
|
|
margin-top: 30px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 响应式调整
|
|
|
@media (max-width: 1200px) {
|
|
|
.member-card-create {
|
|
|
.card-type-list {
|
|
|
.card-type-item {
|
|
|
.card-type-details {
|
|
|
.detail-item {
|
|
|
flex-direction: column;
|
|
|
align-items: flex-start;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
.member-card-create {
|
|
|
.page-header {
|
|
|
flex-direction: column;
|
|
|
align-items: flex-start;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
.step-content {
|
|
|
.section-title {
|
|
|
flex-direction: column;
|
|
|
align-items: flex-start;
|
|
|
gap: 10px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</style>
|