()
| 806 | } |
| 807 | |
| 808 | function saveCurrentAsTemplate() { |
| 809 | const name = getInputValue("billing-template-name"); |
| 810 | if (!name) { |
| 811 | toast.warning("请先填写模板名称"); |
| 812 | return; |
| 813 | } |
| 814 | |
| 815 | const form = normalizeTemplateData(collectBillingFormData()); |
| 816 | const hasValue = Boolean( |
| 817 | form.card_number || |
| 818 | (form.exp_month && form.exp_year) || |
| 819 | form.cvc || |
| 820 | form.billing_name || |
| 821 | form.address_line1 |
| 822 | ); |
| 823 | if (!hasValue) { |
| 824 | toast.warning("当前表单为空,无法保存模板"); |
| 825 | return; |
| 826 | } |
| 827 | |
| 828 | const templates = getBillingTemplates(); |
| 829 | const normalizedName = name.toLowerCase(); |
| 830 | const existing = templates.find((tpl) => String(tpl.name || "").toLowerCase() === normalizedName); |
| 831 | const nowIso = new Date().toISOString(); |
| 832 | if (existing) { |
| 833 | existing.data = form; |
| 834 | existing.updated_at = nowIso; |
| 835 | saveBillingTemplates(templates); |
| 836 | refreshBillingTemplateSelect(existing.id); |
| 837 | toast.success(`模板已更新: ${name}`); |
| 838 | return; |
| 839 | } |
| 840 | |
| 841 | const newTemplate = { |
| 842 | id: `tpl_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`, |
| 843 | name, |
| 844 | data: form, |
| 845 | created_at: nowIso, |
| 846 | updated_at: nowIso, |
| 847 | }; |
| 848 | templates.unshift(newTemplate); |
| 849 | saveBillingTemplates(templates); |
| 850 | refreshBillingTemplateSelect(newTemplate.id); |
| 851 | toast.success(`模板已保存: ${name}`); |
| 852 | } |
| 853 | |
| 854 | function applySelectedTemplate() { |
| 855 | const selectEl = document.getElementById("billing-template-select"); |
nothing calls this directly
no test coverage detected