()
| 895 | } |
| 896 | |
| 897 | function saveBatchProfilesAsTemplates() { |
| 898 | if (!billingBatchProfiles.length) { |
| 899 | toast.warning("请先批量识别文本"); |
| 900 | return; |
| 901 | } |
| 902 | |
| 903 | const templates = getBillingTemplates(); |
| 904 | const now = new Date(); |
| 905 | let saved = 0; |
| 906 | |
| 907 | billingBatchProfiles.forEach((item, idx) => { |
| 908 | const parsed = item?.parsed || {}; |
| 909 | const data = normalizeTemplateData({ |
| 910 | card_number: parsed.card_number, |
| 911 | exp_month: parsed.exp_month, |
| 912 | exp_year: parsed.exp_year, |
| 913 | cvc: parsed.cvv, |
| 914 | billing_name: parsed.billing_name, |
| 915 | country_code: parsed.country_code, |
| 916 | currency: parsed.currency, |
| 917 | address_line1: parsed.address_line1, |
| 918 | address_city: parsed.address_city, |
| 919 | address_state: parsed.address_state, |
| 920 | postal_code: parsed.postal_code, |
| 921 | }); |
| 922 | const hasValue = Boolean( |
| 923 | data.card_number || |
| 924 | (data.exp_month && data.exp_year) || |
| 925 | data.cvc || |
| 926 | data.billing_name || |
| 927 | data.address_line1 |
| 928 | ); |
| 929 | if (!hasValue) return; |
| 930 | |
| 931 | const suffix = data.card_number ? data.card_number.slice(-4) : String(idx + 1).padStart(2, "0"); |
| 932 | const name = `批量模板-${now.toISOString().slice(0, 10)}-${suffix}`; |
| 933 | templates.unshift({ |
| 934 | id: `tpl_${Date.now()}_${Math.random().toString(16).slice(2, 8)}_${idx}`, |
| 935 | name, |
| 936 | data, |
| 937 | created_at: now.toISOString(), |
| 938 | updated_at: now.toISOString(), |
| 939 | }); |
| 940 | saved += 1; |
| 941 | }); |
| 942 | |
| 943 | if (!saved) { |
| 944 | toast.warning("批量记录里没有可保存的模板"); |
| 945 | return; |
| 946 | } |
| 947 | |
| 948 | saveBillingTemplates(templates); |
| 949 | refreshBillingTemplateSelect(); |
| 950 | toast.success(`已保存 ${saved} 个模板`); |
| 951 | } |
| 952 | |
| 953 | function setParseResult(message, type = "info") { |
| 954 | const resultEl = document.getElementById("billing-parse-result"); |
nothing calls this directly
no test coverage detected