newVoucher.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. <template>
  2. <!-- 代金券管理 - 新增/编辑页面 -->
  3. <div class="table-box" style="width: 100%; min-height: 100%; background-color: white">
  4. <div class="header">
  5. <el-button @click="goBack"> 返回 </el-button>
  6. <h2 class="title">新建代金券</h2>
  7. </div>
  8. <el-form :model="voucherModel" ref="ruleFormRef" :rules="rules" label-width="120px" class="formBox">
  9. <div class="content">
  10. <!-- 左侧内容区域 -->
  11. <div class="contentLeft">
  12. <!-- 基础信息模块 -->
  13. <div class="model">
  14. <h3 style="font-weight: bold">基础信息:</h3>
  15. <!-- 代金券名称 -->
  16. <el-form-item label="代金券名称" prop="voucherName">
  17. <el-input maxlength="50" v-model="voucherModel.voucherName" placeholder="请输入" clearable />
  18. </el-form-item>
  19. <!-- 抵扣价格 -->
  20. <el-form-item label="抵扣价格(¥)" prop="discountPrice">
  21. <el-input v-model="voucherModel.discountPrice" maxlength="15" placeholder="请输入" clearable />
  22. </el-form-item>
  23. <!-- 售卖价格 -->
  24. <el-form-item label="售卖价格(¥)" prop="sellingPrice">
  25. <el-input v-model="voucherModel.sellingPrice" maxlength="15" placeholder="请输入" clearable />
  26. </el-form-item>
  27. <!-- 开始售卖时间 -->
  28. <el-form-item label="开始售卖时间" prop="startSellingTime">
  29. <el-date-picker
  30. v-model="voucherModel.startSellingTime"
  31. format="YYYY/MM/DD"
  32. value-format="YYYY-MM-DD"
  33. placeholder="请选择开始售卖时间"
  34. :disabled-date="disabledStartDate"
  35. />
  36. </el-form-item>
  37. <!-- 结束售卖时间 -->
  38. <el-form-item label="结束售卖时间" prop="endSellingTime">
  39. <el-date-picker
  40. v-model="voucherModel.endSellingTime"
  41. format="YYYY/MM/DD"
  42. value-format="YYYY-MM-DD"
  43. placeholder="请选择结束售卖时间"
  44. :disabled-date="disabledEndDate"
  45. />
  46. </el-form-item>
  47. </div>
  48. <!-- 购买须知模块 -->
  49. <div class="model">
  50. <h3 style="font-weight: bold">购买须知:</h3>
  51. <!-- 使用时间 -->
  52. <el-form-item label="使用时间" prop="usageTime">
  53. <el-date-picker
  54. v-model="voucherModel.usageTime"
  55. type="daterange"
  56. value-format="YYYY-MM-DD"
  57. range-separator="-"
  58. start-placeholder="开始时间"
  59. end-placeholder="结束时间"
  60. :disabled-date="disabledUsageDate"
  61. />
  62. </el-form-item>
  63. <!-- 有效期 -->
  64. <el-form-item label="有效期" prop="validityPeriodType">
  65. <el-radio-group v-model="voucherModel.validityPeriodType" class="ml-4">
  66. <el-radio v-for="status in validityPeriodList" :value="status.value" :key="status.value">
  67. {{ status.label }}
  68. </el-radio>
  69. </el-radio-group>
  70. </el-form-item>
  71. <el-form-item label="" prop="validityDays" v-if="voucherModel.validityPeriodType == 0">
  72. <div class="expiration-date-container">
  73. <span class="expiration-label">用户购买</span>
  74. <el-input-number v-model="voucherModel.validityDays" placeholder="请输入" :min="1" class="expiration-input" />
  75. <span class="expiration-label">天内有效</span>
  76. </div>
  77. </el-form-item>
  78. <el-form-item label="" prop="validityPeriod" v-else>
  79. <el-date-picker
  80. v-model="voucherModel.validityPeriod"
  81. type="daterange"
  82. value-format="YYYY-MM-DD"
  83. range-separator="-"
  84. start-placeholder="开始时间"
  85. end-placeholder="结束时间"
  86. :disabled-date="disabledValidityDate"
  87. />
  88. </el-form-item>
  89. <!-- 不可用日期 -->
  90. <el-form-item label="不可用日期" prop="unavailableDateType">
  91. <el-radio-group v-model="voucherModel.unavailableDateType" class="ml-4">
  92. <el-radio v-for="status in unavailableDateTypeList" :value="status.value" :key="status.value">
  93. {{ status.label }}
  94. </el-radio>
  95. </el-radio-group>
  96. </el-form-item>
  97. <template v-if="voucherModel.unavailableDateType == 1">
  98. <el-form-item label="" prop="unavailableWeekdays">
  99. <div class="unavailable-dates-container">
  100. <!-- 星期选择 -->
  101. <div class="date-select-section">
  102. <div class="section-title">星期</div>
  103. <div class="button-group">
  104. <el-button
  105. v-for="weekday in weekdayList"
  106. :key="weekday.oName"
  107. :type="voucherModel.unavailableWeekdays?.includes(weekday.oName) ? 'primary' : ''"
  108. class="date-select-btn"
  109. @click="toggleWeekday(weekday.oName)"
  110. >
  111. {{ weekday.name }}
  112. </el-button>
  113. </div>
  114. </div>
  115. </div>
  116. </el-form-item>
  117. <el-form-item label="" prop="unavailableHolidays">
  118. <div class="unavailable-dates-container">
  119. <!-- 节日选择 -->
  120. <div class="date-select-section">
  121. <div class="section-title">节日</div>
  122. <div class="button-group">
  123. <el-button
  124. v-for="holiday in holidayList"
  125. :key="holiday.id"
  126. :type="voucherModel.unavailableHolidays?.includes(holiday.id) ? 'primary' : ''"
  127. class="date-select-btn"
  128. @click="toggleHoliday(holiday.id)"
  129. >
  130. {{ holiday.festivalName }}
  131. </el-button>
  132. </div>
  133. </div>
  134. </div>
  135. </el-form-item>
  136. </template>
  137. <el-form-item label="" prop="customUnavailableDates" v-else-if="voucherModel.unavailableDateType == 2">
  138. <div class="date-picker-container">
  139. <el-button :icon="Plus" class="add-date-btn" type="primary" @click="addDate"> 添加日期 </el-button>
  140. <div v-for="(item, index) in dates" :key="index" class="date-item">
  141. <el-date-picker
  142. v-model="dates[index]"
  143. type="daterange"
  144. value-format="YYYY-MM-DD"
  145. range-separator="-"
  146. start-placeholder="开始时间"
  147. end-placeholder="结束时间"
  148. class="date-picker"
  149. :disabled-date="disabledCustomUnavailableDate"
  150. />
  151. <el-button
  152. :icon="Delete"
  153. type="danger"
  154. circle
  155. size="small"
  156. class="delete-btn"
  157. @click="removeDate(index)"
  158. v-show="dates.length > 1"
  159. />
  160. </div>
  161. </div>
  162. </el-form-item>
  163. </div>
  164. </div>
  165. <!-- 右侧内容区域 -->
  166. <div class="contentRight">
  167. <!-- 库存模块 -->
  168. <div class="model">
  169. <h3 style="font-weight: bold">库存:</h3>
  170. <el-form-item label="库存" prop="inventory">
  171. <el-input v-model="voucherModel.inventory" maxlength="15" placeholder="请输入" clearable />
  172. </el-form-item>
  173. </div>
  174. <!-- 使用规则模块 -->
  175. <div class="model">
  176. <h3 style="font-weight: bold">使用规则:</h3>
  177. <!-- 单日可用数量 -->
  178. <el-form-item label="单日可用数量" prop="dailyAvailableQuantity">
  179. <el-input v-model="voucherModel.dailyAvailableQuantity" maxlength="15" placeholder="请输入" clearable />
  180. </el-form-item>
  181. <!-- 限购数量 -->
  182. <el-form-item label="限购数量" prop="purchaseLimitQuantity">
  183. <el-input v-model="voucherModel.purchaseLimitQuantity" maxlength="15" placeholder="请输入" clearable />
  184. </el-form-item>
  185. <!-- 适用范围 -->
  186. <el-form-item label="适用范围" prop="applicableScopeType">
  187. <el-radio-group v-model="voucherModel.applicableScopeType" class="ml-4">
  188. <el-radio v-for="status in applicableScopeList" :value="status.value" :key="status.value">
  189. {{ status.label }}
  190. </el-radio>
  191. </el-radio-group>
  192. </el-form-item>
  193. <el-form-item label="" prop="applicableScope" v-if="voucherModel.applicableScopeType == 1">
  194. <el-input
  195. maxlength="50"
  196. v-model="voucherModel.applicableScope"
  197. :rows="3"
  198. type="textarea"
  199. placeholder="请输入"
  200. show-word-limit
  201. />
  202. </el-form-item>
  203. </div>
  204. <!-- 补充说明模块 -->
  205. <div class="model">
  206. <h3 style="font-weight: bold">补充说明:</h3>
  207. <el-form-item label="补充说明" prop="additionalInstructions">
  208. <el-input
  209. maxlength="300"
  210. v-model="voucherModel.additionalInstructions"
  211. :rows="4"
  212. type="textarea"
  213. placeholder="请输入"
  214. show-word-limit
  215. />
  216. </el-form-item>
  217. </div>
  218. </div>
  219. </div>
  220. </el-form>
  221. <!-- 底部按钮区域 -->
  222. <div class="button-container">
  223. <el-button @click="handleSubmit('draft')"> 存草稿 </el-button>
  224. <el-button type="primary" @click="handleSubmit"> 新建代金券 </el-button>
  225. </div>
  226. </div>
  227. </template>
  228. <script setup lang="tsx" name="newVoucher">
  229. /**
  230. * 代金券管理 - 新增/编辑页面
  231. * 功能:支持代金券的新增和编辑操作
  232. */
  233. import { ref, reactive, watch, nextTick, onMounted } from "vue";
  234. import { ElMessage } from "element-plus";
  235. import { useRoute, useRouter } from "vue-router";
  236. import type { FormInstance } from "element-plus";
  237. import { getVoucherDetail } from "@/api/modules/voucherManagement";
  238. import {
  239. validatePositiveNumber,
  240. validatePositiveInteger,
  241. validateDateRange,
  242. validateDateRangeArray,
  243. validateConditionalRequired,
  244. validateArrayMinLength,
  245. validateDateListArray
  246. } from "@/utils/eleValidate";
  247. // ==================== 响应式数据定义 ====================
  248. // 路由相关
  249. const router = useRouter();
  250. const route = useRoute();
  251. // 页面状态
  252. const type = ref<string>(""); // 页面类型:add-新增, edit-编辑
  253. const id = ref<string>(""); // 页面ID参数
  254. // ==================== 表单验证规则 ====================
  255. const rules = reactive({
  256. voucherName: [{ required: true, message: "请输入代金券名称" }],
  257. discountPrice: [
  258. { required: true, message: "请输入抵扣价格" },
  259. {
  260. validator: validatePositiveNumber("抵扣价格必须为正数"),
  261. trigger: "blur"
  262. }
  263. ],
  264. sellingPrice: [
  265. { required: true, message: "请输入售卖价格" },
  266. {
  267. validator: validatePositiveNumber("售卖价格必须为正数"),
  268. trigger: "blur"
  269. }
  270. ],
  271. startSellingTime: [
  272. { required: true, message: "请选择开始售卖时间" },
  273. {
  274. validator: validateDateRange(
  275. () => voucherModel.value.startSellingTime,
  276. () => voucherModel.value.endSellingTime,
  277. "开始售卖时间不能早于当前时间",
  278. "结束售卖时间不能早于当前时间",
  279. "开始售卖时间必须早于结束售卖时间",
  280. true
  281. ),
  282. trigger: "change"
  283. }
  284. ],
  285. endSellingTime: [
  286. { required: true, message: "请选择结束售卖时间" },
  287. {
  288. validator: validateDateRange(
  289. () => voucherModel.value.startSellingTime,
  290. () => voucherModel.value.endSellingTime,
  291. "开始售卖时间不能早于当前时间",
  292. "结束售卖时间不能早于当前时间",
  293. "开始售卖时间必须早于结束售卖时间",
  294. true
  295. ),
  296. trigger: "change"
  297. }
  298. ],
  299. usageTime: [
  300. { required: true, message: "请选择使用时间" },
  301. {
  302. validator: validateDateRangeArray("使用开始时间必须早于结束时间"),
  303. trigger: "change"
  304. }
  305. ],
  306. validityPeriodType: [{ required: true, message: "请选择有效期类型" }],
  307. validityDays: [
  308. {
  309. required: true,
  310. validator: (rule: any, value: any, callback: any) => {
  311. if (voucherModel.value.validityPeriodType === 0) {
  312. if (value === null || value === undefined || value === "") {
  313. callback(new Error("请输入用户购买天数"));
  314. return;
  315. }
  316. if (value <= 0) {
  317. callback(new Error("天数必须大于0"));
  318. return;
  319. }
  320. }
  321. callback();
  322. },
  323. trigger: "blur"
  324. }
  325. ],
  326. validityPeriod: [
  327. {
  328. required: true,
  329. validator: validateConditionalRequired(() => voucherModel.value.validityPeriodType === 1, "请选择指定时间段"),
  330. trigger: "change"
  331. },
  332. {
  333. validator: (rule: any, value: any, callback: any) => {
  334. if (voucherModel.value.validityPeriodType === 1 && value && value.length === 2) {
  335. validateDateRangeArray("开始时间必须早于结束时间")(rule, value, callback);
  336. } else {
  337. callback();
  338. }
  339. },
  340. trigger: "change"
  341. }
  342. ],
  343. unavailableDateType: [{ required: true, message: "请选择不可用日期类型" }],
  344. unavailableWeekdays: [
  345. {
  346. validator: validateConditionalRequired(() => voucherModel.value.unavailableDateType === 1, "至少需要选择一个星期"),
  347. trigger: "change"
  348. }
  349. ],
  350. unavailableHolidays: [
  351. {
  352. validator: validateConditionalRequired(() => voucherModel.value.unavailableDateType === 1, "至少需要选择一个节日"),
  353. trigger: "change"
  354. }
  355. ],
  356. customUnavailableDates: [
  357. {
  358. validator: validateConditionalRequired(
  359. () => voucherModel.value.unavailableDateType === 2,
  360. "至少需要添加一个自定义不可用日期"
  361. ),
  362. trigger: "change"
  363. },
  364. {
  365. validator: validateDateListArray(() => dates.value, "日期项未完整填写", "开始时间必须早于结束时间", false),
  366. trigger: "change"
  367. }
  368. ],
  369. inventory: [
  370. { required: true, message: "请输入库存" },
  371. {
  372. validator: validatePositiveInteger("库存必须为正整数", { required: false }),
  373. trigger: "blur"
  374. }
  375. ],
  376. dailyAvailableQuantity: [
  377. {
  378. validator: validatePositiveInteger("单日可用数量必须为正整数", { required: false }),
  379. trigger: "blur"
  380. }
  381. ],
  382. purchaseLimitQuantity: [
  383. {
  384. validator: validatePositiveInteger("限购数量必须为正整数", { required: false }),
  385. trigger: "blur"
  386. }
  387. ],
  388. applicableScopeType: [{ required: true, message: "请选择适用范围类型" }],
  389. applicableScope: [
  390. {
  391. validator: validateConditionalRequired(() => voucherModel.value.applicableScopeType === 1, "请输入适用范围"),
  392. trigger: "blur"
  393. }
  394. ]
  395. });
  396. // ==================== 代金券信息数据模型 ====================
  397. const voucherModel = ref<any>({
  398. // 代金券名称
  399. voucherName: "",
  400. // 抵扣价格
  401. discountPrice: "",
  402. // 售卖价格
  403. sellingPrice: "",
  404. // 开始售卖时间
  405. startSellingTime: "",
  406. // 结束售卖时间
  407. endSellingTime: "",
  408. // 使用时间
  409. usageTime: [],
  410. // 有效期类型:0-指定天数,1-指定时间段内可用
  411. validityPeriodType: 0,
  412. // 有效期天数(当validityPeriodType为0时使用)
  413. validityDays: 90,
  414. // 有效期时间段(当validityPeriodType为1时使用)
  415. validityPeriod: [],
  416. // 不可用日期类型:0-全部日期可用,1-限制日期,2-自定义不可用日期
  417. unavailableDateType: 0,
  418. // 限制日期 - 星期选择(数组,存储选中的星期值)
  419. unavailableWeekdays: [],
  420. // 限制日期 - 节日选择(数组,存储选中的节日值)
  421. unavailableHolidays: [],
  422. // 库存
  423. inventory: "",
  424. // 单日可用数量
  425. dailyAvailableQuantity: "",
  426. // 限购数量
  427. purchaseLimitQuantity: "",
  428. // 适用范围类型:0-全场通用,1-部分不可用
  429. applicableScopeType: 0,
  430. // 适用范围(当applicableScopeType为1时使用)
  431. applicableScope: "",
  432. // 补充说明
  433. additionalInstructions: ""
  434. });
  435. // ==================== 下拉选项数据 ====================
  436. // 有效期类型列表
  437. const validityPeriodList = ref([
  438. { value: 0, label: "指定天数" },
  439. { value: 1, label: "指定时间段内可用" }
  440. ]);
  441. // 不可用日期类型列表
  442. const unavailableDateTypeList = ref([
  443. { value: 0, label: "全部日期可用" },
  444. { value: 1, label: "限制日期" },
  445. { value: 2, label: "自定义不可用日期" }
  446. ]);
  447. // 适用范围类型列表
  448. const applicableScopeList = ref([
  449. { value: 0, label: "全场通用" },
  450. { value: 1, label: "部分不可用" }
  451. ]);
  452. // 自定义不可用日期列表
  453. const dates = ref([]);
  454. // 星期选项列表
  455. const weekdayList = ref([
  456. { name: "周一", id: "0", oName: "星期一" },
  457. { name: "周二", id: "1", oName: "星期二" },
  458. { name: "周三", id: "2", oName: "星期三" },
  459. { name: "周四", id: "3", oName: "星期四" },
  460. { name: "周五", id: "4", oName: "星期五" },
  461. { name: "周六", id: "5", oName: "星期六" },
  462. { name: "周日", id: "6", oName: "星期日" }
  463. ]);
  464. // 节日选项列表
  465. const holidayList: any = ref([]);
  466. // ==================== 监听器 ====================
  467. /**
  468. * 监听不可用日期选项变化
  469. * 当切换到自定义不可用日期时,确保至少有一个日期项
  470. */
  471. watch(
  472. () => voucherModel.value.unavailableDateType,
  473. newVal => {
  474. if (newVal === 2) {
  475. if (!dates.value || dates.value.length === 0) {
  476. dates.value = [null];
  477. }
  478. }
  479. },
  480. { immediate: true }
  481. );
  482. /**
  483. * 监听开始售卖时间变化
  484. * 当开始时间改变时,重新验证结束时间
  485. */
  486. watch(
  487. () => voucherModel.value.startSellingTime,
  488. () => {
  489. if (voucherModel.value.endSellingTime) {
  490. nextTick(() => {
  491. ruleFormRef.value?.validateField("endSellingTime");
  492. });
  493. }
  494. }
  495. );
  496. /**
  497. * 监听结束售卖时间变化
  498. * 当结束时间改变时,重新验证开始时间
  499. */
  500. watch(
  501. () => voucherModel.value.endSellingTime,
  502. () => {
  503. if (voucherModel.value.startSellingTime) {
  504. nextTick(() => {
  505. ruleFormRef.value?.validateField("startSellingTime");
  506. });
  507. }
  508. }
  509. );
  510. // ==================== 生命周期钩子 ====================
  511. /**
  512. * 组件挂载时初始化
  513. * 从路由参数中获取页面类型和ID
  514. */
  515. onMounted(async () => {
  516. id.value = (route.query.id as string) || "";
  517. type.value = (route.query.type as string) || "";
  518. // 编辑模式下加载数据
  519. if (type.value != "add") {
  520. // TODO: 加载代金券详情数据
  521. // let res: any = await getVoucherDetail({ id: id.value });
  522. // voucherModel.value = res.data;
  523. }
  524. });
  525. // ==================== 事件处理函数 ====================
  526. /**
  527. * 返回上一页
  528. */
  529. const goBack = () => {
  530. router.go(-1);
  531. };
  532. /**
  533. * 添加自定义不可用日期
  534. */
  535. const addDate = () => {
  536. dates.value.push(null);
  537. };
  538. /**
  539. * 删除自定义不可用日期
  540. * @param index 要删除的日期索引
  541. */
  542. const removeDate = (index: number) => {
  543. if (dates.value.length <= 1) {
  544. ElMessage.warning("至少需要保留一个日期项");
  545. return;
  546. }
  547. dates.value.splice(index, 1);
  548. };
  549. /**
  550. * 切换星期选择
  551. * @param value 星期值
  552. */
  553. const toggleWeekday = (value: string) => {
  554. if (!voucherModel.value.unavailableWeekdays) {
  555. voucherModel.value.unavailableWeekdays = [];
  556. }
  557. const index = voucherModel.value.unavailableWeekdays.indexOf(value);
  558. if (index > -1) {
  559. voucherModel.value.unavailableWeekdays.splice(index, 1);
  560. } else {
  561. voucherModel.value.unavailableWeekdays.push(value);
  562. }
  563. // 触发表单验证
  564. nextTick(() => {
  565. ruleFormRef.value?.validateField("unavailableWeekdays");
  566. });
  567. };
  568. /**
  569. * 切换节日选择
  570. * @param value 节日值
  571. */
  572. const toggleHoliday = (value: string | number) => {
  573. if (!voucherModel.value.unavailableHolidays) {
  574. voucherModel.value.unavailableHolidays = [];
  575. }
  576. const index = voucherModel.value.unavailableHolidays.indexOf(value);
  577. if (index > -1) {
  578. voucherModel.value.unavailableHolidays.splice(index, 1);
  579. } else {
  580. voucherModel.value.unavailableHolidays.push(value);
  581. }
  582. // 触发表单验证
  583. nextTick(() => {
  584. ruleFormRef.value?.validateField("unavailableHolidays");
  585. });
  586. };
  587. // ==================== 表单引用 ====================
  588. const ruleFormRef = ref<FormInstance>(); // 表单引用
  589. /**
  590. * 提交数据(新增/编辑)
  591. * 验证表单,通过后调用相应的API接口
  592. */
  593. const handleSubmit = (submitType?: string) => {
  594. // 验证表单
  595. ruleFormRef.value!.validate(async (valid: boolean) => {
  596. if (!valid) return;
  597. // 组装提交参数
  598. let params: any = { ...voucherModel.value };
  599. // 处理有效期
  600. if (params.validityPeriodType === 0) {
  601. params.validityPeriodStr = `用户购买${params.validityDays}天内有效`;
  602. } else {
  603. params.validityPeriodStr = params.validityPeriod.join(",");
  604. }
  605. // 处理不可用日期
  606. if (params.unavailableDateType === 1) {
  607. params.unavailableDateValue = params.unavailableWeekdays.join(",") + ";" + params.unavailableHolidays.join(",");
  608. } else if (params.unavailableDateType === 2) {
  609. params.unavailableDateValue = dates.value.map((subArray: any) => subArray.join(",")).join(";");
  610. }
  611. // 处理使用时间
  612. if (params.usageTime && params.usageTime.length === 2) {
  613. params.usageStartTime = params.usageTime[0];
  614. params.usageEndTime = params.usageTime[1];
  615. }
  616. console.log("提交参数:", params);
  617. // TODO: 调用API保存数据
  618. // if (submitType === 'draft') {
  619. // await saveVoucherDraft(params);
  620. // } else {
  621. // await saveVoucher(params);
  622. // }
  623. if (submitType === "draft") {
  624. ElMessage.success("草稿保存成功");
  625. } else {
  626. ElMessage.success("代金券创建成功");
  627. router.go(-1);
  628. }
  629. });
  630. };
  631. // ==================== 工具函数 ====================
  632. /**
  633. * 禁用开始售卖时间的日期
  634. * 不能选择早于当前时间的日期
  635. */
  636. const disabledStartDate = (time: Date) => {
  637. const today = new Date();
  638. today.setHours(0, 0, 0, 0);
  639. return time.getTime() < today.getTime();
  640. };
  641. /**
  642. * 禁用结束售卖时间的日期
  643. * 不能选择早于当前时间的日期,也不能选择早于或等于开始售卖时间的日期
  644. */
  645. const disabledEndDate = (time: Date) => {
  646. const today = new Date();
  647. today.setHours(0, 0, 0, 0);
  648. if (time.getTime() < today.getTime()) {
  649. return true;
  650. }
  651. if (voucherModel.value.startSellingTime) {
  652. const startDate = new Date(voucherModel.value.startSellingTime);
  653. startDate.setHours(0, 0, 0, 0);
  654. return time.getTime() <= startDate.getTime();
  655. }
  656. return false;
  657. };
  658. /**
  659. * 禁用使用时间的日期
  660. */
  661. const disabledUsageDate = (time: Date) => {
  662. return false; // 可以根据需要添加限制
  663. };
  664. /**
  665. * 禁用有效期时间段的日期
  666. */
  667. const disabledValidityDate = (time: Date) => {
  668. return false; // 可以根据需要添加限制
  669. };
  670. /**
  671. * 禁用自定义不可用日期的日期
  672. */
  673. const disabledCustomUnavailableDate = (time: Date) => {
  674. return false; // 可以根据需要添加限制
  675. };
  676. </script>
  677. <style scoped lang="scss">
  678. /* 页面容器 */
  679. .table-box {
  680. display: flex;
  681. flex-direction: column;
  682. height: auto !important;
  683. min-height: 100%;
  684. }
  685. /* 头部区域 */
  686. .header {
  687. display: flex;
  688. align-items: center;
  689. padding: 20px;
  690. border-bottom: 1px solid #e4e7ed;
  691. }
  692. .title {
  693. flex: 1;
  694. margin: 0;
  695. font-size: 18px;
  696. font-weight: bold;
  697. text-align: center;
  698. }
  699. /* 内容区域布局 */
  700. .content {
  701. display: flex;
  702. flex: 1;
  703. column-gap: 20px;
  704. width: 98%;
  705. margin: 20px auto;
  706. /* 左侧内容区域 */
  707. .contentLeft {
  708. width: 50%;
  709. }
  710. /* 右侧内容区域 */
  711. .contentRight {
  712. width: 50%;
  713. }
  714. }
  715. /* 模块容器 */
  716. .model {
  717. margin-bottom: 50px;
  718. }
  719. /* 表单容器 */
  720. .formBox {
  721. display: flex;
  722. flex-direction: column;
  723. width: 100%;
  724. min-height: 100%;
  725. }
  726. /* 底部按钮容器 - 居中显示 */
  727. .button-container {
  728. display: flex;
  729. gap: 12px;
  730. align-items: center;
  731. justify-content: center;
  732. padding: 20px 0;
  733. margin-top: 20px;
  734. }
  735. /* 日期选择器容器 */
  736. .date-picker-container {
  737. display: flex;
  738. flex-direction: column;
  739. gap: 12px;
  740. width: 100%;
  741. }
  742. /* 添加日期按钮 */
  743. .add-date-btn {
  744. width: fit-content;
  745. margin-bottom: 8px;
  746. }
  747. /* 日期项容器 */
  748. .date-item {
  749. display: flex;
  750. gap: 12px;
  751. align-items: center;
  752. padding: 8px;
  753. border-radius: 4px;
  754. transition: background-color 0.3s;
  755. &:hover {
  756. background-color: #ecf5ff;
  757. }
  758. }
  759. /* 日期选择器 */
  760. .date-item .date-picker {
  761. flex: 1;
  762. max-width: 500px;
  763. }
  764. /* 删除按钮 */
  765. .date-item .delete-btn {
  766. flex-shrink: 0;
  767. }
  768. /* 有效期天数容器 */
  769. .expiration-date-container {
  770. display: flex;
  771. gap: 12px;
  772. align-items: center;
  773. width: fit-content;
  774. padding: 8px 12px;
  775. border-radius: 4px;
  776. }
  777. /* 有效期标签文字 */
  778. .expiration-label {
  779. font-size: 14px;
  780. color: #606266;
  781. white-space: nowrap;
  782. }
  783. /* 有效期输入框 */
  784. .expiration-input {
  785. width: 150px;
  786. }
  787. /* 不可用日期容器 */
  788. .unavailable-dates-container {
  789. display: flex;
  790. flex-direction: column;
  791. gap: 20px;
  792. width: 100%;
  793. }
  794. /* 日期选择区块 */
  795. .date-select-section {
  796. display: flex;
  797. flex-direction: column;
  798. gap: 12px;
  799. }
  800. /* 区块标题 */
  801. .section-title {
  802. font-size: 14px;
  803. font-weight: 500;
  804. color: #606266;
  805. }
  806. /* 按钮组 */
  807. .button-group {
  808. display: flex;
  809. flex-wrap: wrap;
  810. gap: 10px;
  811. }
  812. /* 日期选择按钮 */
  813. .date-select-btn {
  814. min-width: 80px;
  815. height: 36px;
  816. padding: 8px 16px;
  817. margin: 0;
  818. font-size: 14px;
  819. border-radius: 4px;
  820. transition: all 0.3s;
  821. }
  822. </style>