zz-shopify-components 0.3.1-beta.9 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/aliyun-oss-sdk-6.20.0.min.js +4 -0
- package/assets/crypto-js.min.js +1 -0
- package/assets/zz-components.css +39 -1
- package/assets/zz-components.js +78 -0
- package/assets/zz-edu-info-dialog.js +123 -0
- package/blocks/zz-button.liquid +0 -3
- package/blocks/zz-content-description.liquid +0 -1
- package/blocks/zz-edu-form.liquid +895 -0
- package/blocks/zz-icon.liquid +0 -1
- package/blocks/zz-normal-swiper.liquid +364 -0
- package/blocks/zz-scroll-animate-bg-text.liquid +0 -1
- package/blocks/zz-tag.liquid +0 -1
- package/blocks/zz-video-button.liquid +0 -2
- package/component.config.json +3 -1
- package/docs/zz-normal-swiper.md +215 -0
- package/package.json +1 -1
- package/sections/zz-modal.liquid +1 -1
- package/sections/zz-navigation-tab-v3.liquid +5 -6
- package/sections/zz-navigation-tab.liquid +0 -1
- package/sections/zz-swiper-banner.liquid +1 -11
- package/snippets/zz-edu-info-dialog.liquid +92 -0
- package/snippets/zz-h2.liquid +0 -1
- package/snippets/zz-h3.liquid +0 -1
- package/snippets/zz-h4.liquid +0 -1
- package/snippets/zz-h5.liquid +0 -1
- package/snippets/zz-h6.liquid +0 -1
- package/snippets/zz-video-button.liquid +0 -1
- package/snippets/zz-video-md.liquid +0 -1
- package/snippets/zz-video.liquid +0 -1
- package/snippets/locksmith-content-variables.liquid +0 -54
- package/snippets/locksmith-variables.liquid +0 -10
- package/snippets/locksmith.liquid +0 -152
|
@@ -0,0 +1,895 @@
|
|
|
1
|
+
{% schema %}
|
|
2
|
+
{
|
|
3
|
+
"name": "Edu Form",
|
|
4
|
+
"class": "zz-edu-form",
|
|
5
|
+
"settings": [
|
|
6
|
+
{
|
|
7
|
+
"type": "color_background",
|
|
8
|
+
"id": "background_color",
|
|
9
|
+
"label": "背景颜色",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "select",
|
|
13
|
+
"id": "request_type",
|
|
14
|
+
"label": "请求类型",
|
|
15
|
+
"options": [
|
|
16
|
+
{ "value": "prod", "label": "正式" },
|
|
17
|
+
{ "value": "test", "label": "测试" }
|
|
18
|
+
],
|
|
19
|
+
"default": "test"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"type": "select",
|
|
23
|
+
"id": "site_type",
|
|
24
|
+
"label": "站点",
|
|
25
|
+
"options": [
|
|
26
|
+
{ "value": "us", "label": "US" },
|
|
27
|
+
{ "value": "eu", "label": "EU" }
|
|
28
|
+
],
|
|
29
|
+
"default": "us"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "url",
|
|
33
|
+
"id": "login_url",
|
|
34
|
+
"label": "登录链接"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "text",
|
|
38
|
+
"id": "verify_email_title",
|
|
39
|
+
"label": "验证邮箱标题",
|
|
40
|
+
"default": "Verify my email"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"type": "text",
|
|
44
|
+
"id": "verify_email_message",
|
|
45
|
+
"label": "验证邮箱内容",
|
|
46
|
+
"default": "Verification code sent to your educational email, please check."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": "text",
|
|
50
|
+
"id": "verify_success_title",
|
|
51
|
+
"label": "验证成功标题",
|
|
52
|
+
"default": "Verification successful"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"type": "text",
|
|
56
|
+
"id": "verify_success_message",
|
|
57
|
+
"label": "验证成功内容",
|
|
58
|
+
"default": "Authentication successful. An account activation email has been sent to your email address. Please check your email to complete the activation."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "text",
|
|
62
|
+
"id": "verify_fail_title",
|
|
63
|
+
"label": "验证失败标题",
|
|
64
|
+
"default": "Verification failed"
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
"presets": [
|
|
68
|
+
{
|
|
69
|
+
"name": "Edu Form"
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
{% endschema %}
|
|
75
|
+
|
|
76
|
+
{% assign is_logged_in = false %}
|
|
77
|
+
{% assign is_edu_verified = false %}
|
|
78
|
+
{% if customer %}
|
|
79
|
+
{% assign is_logged_in = true %}
|
|
80
|
+
{% if customer.tags contains 'edu-verified' %}
|
|
81
|
+
{% assign is_edu_verified = true %}
|
|
82
|
+
{% endif %}
|
|
83
|
+
{% endif %}
|
|
84
|
+
|
|
85
|
+
{% if block.settings.site_type == 'us' %}
|
|
86
|
+
{% assign shop_id = 'a0989c' %}
|
|
87
|
+
{% else %}
|
|
88
|
+
{% assign shop_id = 'thehovereu' %}
|
|
89
|
+
{% endif %}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
{% assign eu_country_list = 'Deutschland,Germany,La France,France,España,Italia,Österreich,Belgium,Bulgaria,Croatia,Czech Republic,Denmark,Estonia,Finland,Hungary,Ireland,Latvia,Lithuania,Luxembourg,Monaco,Netherlands,Poland,Portugal,Romania,Slovakia,Slovenia,Sweden' | split: ',' %}
|
|
93
|
+
|
|
94
|
+
<div class="tw-w-full tw-flex tw-flex-col tw-items-center tw-justify-center">
|
|
95
|
+
<zz-radio-tabs name="edu-form-type" class="tw-bg-[#F5F5F6] lg:tw-w-[388px]">
|
|
96
|
+
<zz-radio-tabs-item value="email" checked>Verify my email</zz-radio-tabs-item>
|
|
97
|
+
<zz-radio-tabs-item value="manual">Upload student card</zz-radio-tabs-item>
|
|
98
|
+
</zz-radio-tabs>
|
|
99
|
+
<div class="zz-edu-form-container">
|
|
100
|
+
<form class="zz-edu-form-form" id="eduForm-{{ block.id }}">
|
|
101
|
+
<div class="zz-edu-form-group">
|
|
102
|
+
<label for="firstName" class="zz-edu-form-label">Full name</label>
|
|
103
|
+
<div class="zz-edu-form-row">
|
|
104
|
+
<input class="zz-edu-form-input-column" type="text" id="firstName" name="firstName" placeholder="First name" required>
|
|
105
|
+
<input class="zz-edu-form-input-column" type="text" id="lastName" name="lastName" placeholder="Last name" required>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="zz-edu-form-row">
|
|
109
|
+
<!-- 左列 -->
|
|
110
|
+
<div class="zz-edu-form-column">
|
|
111
|
+
<div class="zz-edu-form-group">
|
|
112
|
+
<label for="country" class="zz-edu-form-label">Country</label>
|
|
113
|
+
<select id="country" name="country" class="zz-edu-form-select" required>
|
|
114
|
+
{% if block.settings.site_type == 'us' %}
|
|
115
|
+
<option value="United States" checked>United States</option>
|
|
116
|
+
{% else %}
|
|
117
|
+
{% for country in eu_country_list %}
|
|
118
|
+
<option value="{{ country }}">{{ country }}</option>
|
|
119
|
+
{% endfor %}
|
|
120
|
+
{% endif %}
|
|
121
|
+
</select>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<!-- 右列 -->
|
|
126
|
+
<div class="zz-edu-form-column">
|
|
127
|
+
<div class="zz-edu-form-group">
|
|
128
|
+
<label for="university" class="zz-edu-form-label">University</label>
|
|
129
|
+
<input type="text" id="university" name="university" placeholder="University Name" required>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<div class="zz-edu-form-row">
|
|
135
|
+
<div class="zz-edu-form-column">
|
|
136
|
+
<div class="zz-edu-form-group">
|
|
137
|
+
<label for="email" class="zz-edu-form-label">Email Address</label>
|
|
138
|
+
<input type="email" id="email" name="email" placeholder="example@example.com" required>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
</div>
|
|
142
|
+
<div class="zz-edu-form-column">
|
|
143
|
+
<div class="zz-edu-form-group">
|
|
144
|
+
<label for="phone" class="zz-edu-form-label">Phone Number</label>
|
|
145
|
+
<input type="text" id="phone" name="phone" placeholder="Phone Number" required>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
</div>
|
|
152
|
+
<div class="zz-edu-form-row">
|
|
153
|
+
<!-- 左列 -->
|
|
154
|
+
<div class="zz-edu-form-column">
|
|
155
|
+
<div class="zz-edu-form-group">
|
|
156
|
+
<label for="identityType" class="zz-edu-form-label">Identity Type</label>
|
|
157
|
+
<select id="identityType" name="identityType" class="zz-edu-form-select" required>
|
|
158
|
+
<option value="student" checked>Student</option>
|
|
159
|
+
<option value="parent">Parent</option>
|
|
160
|
+
<option value="teacher">Teacher</option>
|
|
161
|
+
</select>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
</div>
|
|
166
|
+
<div class="zz-edu-form-column"> </div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div class="zz-edu-form-row upload-file-row zz-edu-form-hidden">
|
|
170
|
+
<div class="zz-edu-form-column">
|
|
171
|
+
<div class="zz-edu-form-group">
|
|
172
|
+
<label for="fileUpload-{{ block.id }}" class="zz-edu-form-label">Upload Document</label>
|
|
173
|
+
<div class="zz-edu-form-file-upload-container">
|
|
174
|
+
<input type="file" id="fileUpload-{{ block.id }}" name="fileUpload" class="zz-edu-form-file-input" accept=".pdf,.jpg,.jpeg,.png">
|
|
175
|
+
<label for="fileUpload-{{ block.id }}" class="zz-edu-form-file-upload-label">
|
|
176
|
+
<div class="zz-edu-form-file-upload-content">
|
|
177
|
+
<svg class="zz-edu-form-file-upload-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
178
|
+
<path d="M12 16L12 8M12 8L15 11M12 8L9 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
179
|
+
<path d="M3 15V16C3 18.8284 3 20.2426 3.87868 21.1213C4.75736 22 6.17157 22 9 22H15C17.8284 22 19.2426 22 20.1213 21.1213C21 20.2426 21 18.8284 21 16V15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
180
|
+
</svg>
|
|
181
|
+
<span class="zz-edu-form-file-upload-text">Choose file or drag here</span>
|
|
182
|
+
<span class="zz-edu-form-file-upload-hint">PDF, JPG, PNG (Max 10MB)</span>
|
|
183
|
+
</div>
|
|
184
|
+
</label>
|
|
185
|
+
<div class="zz-edu-form-file-preview" id="filePreview-{{ block.id }}"></div>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div class="zz-edu-form-submit">
|
|
193
|
+
<button type="submit" class="zz-edu-form-submit-btn tw-h-[36px] md:tw-h-[48px]">
|
|
194
|
+
<span
|
|
195
|
+
class='zz-edu-form-submit-loading tw-hidden tw-daisy-loading tw-daisy-loading-spinner '
|
|
196
|
+
></span>
|
|
197
|
+
Submit</button>
|
|
198
|
+
</div>
|
|
199
|
+
</form>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
{% if block.settings.login_url != blank and is_logged_in == false %}
|
|
203
|
+
<div class="tw-font-[500] tw-text-[#000000B2] tw-text-[14px] tw-leading-[1.5] tw-text-center tw-mt-[24px] md:tw-text-[16px]">
|
|
204
|
+
Already verified? <a href="{{ block.settings.login_url }}" class="tw-text-[#000] tw-underline">Log in to shop</a></div>
|
|
205
|
+
{% endif %}
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
{% render 'zz-edu-info-dialog',
|
|
212
|
+
shop: shop_id,
|
|
213
|
+
verify_success_title: block.settings.verify_success_title,
|
|
214
|
+
verify_success_message: block.settings.verify_success_message,
|
|
215
|
+
verify_fail_title: block.settings.verify_fail_title
|
|
216
|
+
%}
|
|
217
|
+
|
|
218
|
+
<script src="{{ 'aliyun-oss-sdk-6.20.0.min.js' | asset_url }}" defer></script>
|
|
219
|
+
<script src="{{ 'crypto-js.min.js' | asset_url }}" defer></script>
|
|
220
|
+
|
|
221
|
+
<script src="{{ 'zz-edu-info-dialog.js' | asset_url }}" defer></script>
|
|
222
|
+
|
|
223
|
+
<script>
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
var EduErrorCodeConf = {
|
|
228
|
+
201: {
|
|
229
|
+
zh: "该教育邮箱已完成注册,无需重复认证",
|
|
230
|
+
en: "This educational email has been registered, no need to re-authenticate"
|
|
231
|
+
},
|
|
232
|
+
400: {
|
|
233
|
+
zh: "邮箱格式不符合教育邮箱规范,请检查后重试",
|
|
234
|
+
en: "Email format does not meet educational email standards, please check and try again"
|
|
235
|
+
},
|
|
236
|
+
401: {
|
|
237
|
+
zh: "认证方式与历史记录不一致,请使用相同认证方式",
|
|
238
|
+
en: "Authentication method inconsistent with historical records, please use the same authentication method"
|
|
239
|
+
},
|
|
240
|
+
402: {
|
|
241
|
+
zh: "已有相同信息和资料的审核表单已在处理中,无需提交",
|
|
242
|
+
en: "A review form with the same information and materials is already being processed, no need to submit"
|
|
243
|
+
},
|
|
244
|
+
403: {
|
|
245
|
+
zh: "申请拒绝次数已达上限(5次),无法继续提交",
|
|
246
|
+
en: "Application rejection limit reached (5 times), cannot continue to submit"
|
|
247
|
+
},
|
|
248
|
+
404: {
|
|
249
|
+
zh: "审核资料未上传或上传格式不合要求",
|
|
250
|
+
en: "Application review materials not uploaded or upload format does not meet requirements"
|
|
251
|
+
},
|
|
252
|
+
405: {
|
|
253
|
+
zh: "验证码格式错误,请输入正确的 位数字验证码",
|
|
254
|
+
en: "Verification code format is incorrect, please enter the correct six-digit verification code"
|
|
255
|
+
},
|
|
256
|
+
406: {
|
|
257
|
+
zh: "验证码已过期,请重新获取",
|
|
258
|
+
en: "Verification code has expired, please obtain a new one"
|
|
259
|
+
},
|
|
260
|
+
407: {
|
|
261
|
+
zh: "验证码错误,请重新输入",
|
|
262
|
+
en: "Incorrect verification code, please try again"
|
|
263
|
+
},
|
|
264
|
+
429: {
|
|
265
|
+
zh: "验证码发送过于频繁,请 1 分钟后再试",
|
|
266
|
+
en: "Verification code sent too frequently, please try again in 1 minute"
|
|
267
|
+
},
|
|
268
|
+
500: {
|
|
269
|
+
zh: "系统繁忙,请稍后再试",
|
|
270
|
+
en: "System is busy, please try again later"
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
274
|
+
var hasInput = false
|
|
275
|
+
{% if block.settings.request_type == 'prod' %}
|
|
276
|
+
{% assign base_url = 'https://h130-app-server-us.hoverx1.cn' %}
|
|
277
|
+
{% else %}
|
|
278
|
+
{% assign base_url = 'https://h130-app-server-test-us.hoverx1.cn' %}
|
|
279
|
+
{% endif %}
|
|
280
|
+
const verifySuccessTitle = '{{ block.settings.verify_success_title }}';
|
|
281
|
+
const verifySuccessMessage = '{{ block.settings.verify_success_message }}';
|
|
282
|
+
const verifyFailTitle = '{{ block.settings.verify_fail_title }}';
|
|
283
|
+
|
|
284
|
+
const baseUrl = '{{ base_url }}';
|
|
285
|
+
const block = document.getElementById('shopify-block-{{ block.id }}');
|
|
286
|
+
const form = block.querySelector('#eduForm-{{ block.id }}');
|
|
287
|
+
let verifyType = 'email'
|
|
288
|
+
let identityDocumentUrl = ''
|
|
289
|
+
|
|
290
|
+
// 表单提交处理
|
|
291
|
+
form.addEventListener('submit', function(e) {
|
|
292
|
+
e.preventDefault();
|
|
293
|
+
const zzEduInfoDialog = block.querySelector('zz-edu-info-dialog');
|
|
294
|
+
// 获取表单数据
|
|
295
|
+
const formData = new FormData(form);
|
|
296
|
+
const data = Object.fromEntries(formData);
|
|
297
|
+
|
|
298
|
+
// 验证必填字段
|
|
299
|
+
const requiredFields = ['firstName', 'lastName', 'country', 'university', 'email', 'phone', 'identityType'];
|
|
300
|
+
let isValid = true;
|
|
301
|
+
|
|
302
|
+
requiredFields.forEach(field => {
|
|
303
|
+
const input = form.querySelector(`[name="${field}"]`);
|
|
304
|
+
if (input) {
|
|
305
|
+
if (!input.value.trim()) {
|
|
306
|
+
input.classList.add('error');
|
|
307
|
+
isValid = false;
|
|
308
|
+
} else {
|
|
309
|
+
input.classList.remove('error');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// 验证文件上传
|
|
316
|
+
if (verifyType === 'manual') {
|
|
317
|
+
const fileInput = form.querySelector('#fileUpload-{{ block.id }}');
|
|
318
|
+
if (!fileInput.files || fileInput.files.length === 0) {
|
|
319
|
+
fileInput.classList.add('error');
|
|
320
|
+
isValid = false;
|
|
321
|
+
} else {
|
|
322
|
+
fileInput.classList.remove('error');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
// 验证邮箱格式
|
|
328
|
+
const email = form.querySelector('[name="email"]');
|
|
329
|
+
let emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
330
|
+
if (verifyType === 'email') {
|
|
331
|
+
emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]*(\.edu|\.ac|zerozero)(\.[a-zA-Z]{2,})?$/;
|
|
332
|
+
}
|
|
333
|
+
if (email.value && !emailRegex.test(email.value)) {
|
|
334
|
+
email.classList.add('error');
|
|
335
|
+
isValid = false;
|
|
336
|
+
{% comment %} zzShowToast('Please fill in all required fields!'); {% endcomment %}
|
|
337
|
+
zzEduInfoDialog.showModal({
|
|
338
|
+
message: verifyType === 'email' ? 'Email format does not meet educational email standards, please check and try again' : 'Please enter a valid email address',
|
|
339
|
+
showInput: false
|
|
340
|
+
})
|
|
341
|
+
return
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (isValid) {
|
|
345
|
+
// 提交表单数据
|
|
346
|
+
block.querySelector('.zz-edu-form-submit-loading').classList.toggle('tw-hidden');
|
|
347
|
+
// 例如发送到服务器或第三方服务
|
|
348
|
+
httpRequest.post('/shopify/edu_identity_verify_request', {
|
|
349
|
+
shopId: "{{ shop_id }}",
|
|
350
|
+
...data,
|
|
351
|
+
verifyMethod: verifyType == 'email' ? 'Self-service authentication' : 'Manual authentication',
|
|
352
|
+
identityDocumentUrl: identityDocumentUrl
|
|
353
|
+
}, {
|
|
354
|
+
baseUrl: baseUrl
|
|
355
|
+
}).then((res) => {
|
|
356
|
+
if(res.code == 200) {
|
|
357
|
+
if(verifyType == 'email') {
|
|
358
|
+
zzEduInfoDialog.showModal({
|
|
359
|
+
title: '{{ block.settings.verify_email_title }}',
|
|
360
|
+
message: '{{ block.settings.verify_email_message }}',
|
|
361
|
+
showInput: true,
|
|
362
|
+
verifyInfo: {
|
|
363
|
+
recordId: res.data,
|
|
364
|
+
baseUrl: baseUrl,
|
|
365
|
+
email: data.email
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
} else {
|
|
369
|
+
zzEduInfoDialog.showModal({
|
|
370
|
+
message: 'The application has been submitted successfully, please wait patiently for review.',
|
|
371
|
+
showInput: false
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
zzEduInfoDialog.showModal({
|
|
376
|
+
title: '{{ block.settings.verify_fail_title }}',
|
|
377
|
+
message: EduErrorCodeConf[res.code].en || res.message,
|
|
378
|
+
showInput: false
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}).catch((err) => {
|
|
382
|
+
zzShowToast(EduErrorCodeConf[500].en)
|
|
383
|
+
}).finally(() => {
|
|
384
|
+
block.querySelector('.zz-edu-form-submit-loading').classList.toggle('tw-hidden');
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// 显示成功消息
|
|
388
|
+
|
|
389
|
+
{% comment %} form.reset(); {% endcomment %}
|
|
390
|
+
} else {
|
|
391
|
+
zzShowToast('Please fill in all required fields!');
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// 实时验证
|
|
396
|
+
const inputs = form.querySelectorAll('input[required], select[required]');
|
|
397
|
+
inputs.forEach(input => {
|
|
398
|
+
input.addEventListener('blur', function() {
|
|
399
|
+
if (!this.value.trim()) {
|
|
400
|
+
this.classList.add('error');
|
|
401
|
+
} else {
|
|
402
|
+
this.classList.remove('error');
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
input.addEventListener('input', function() {
|
|
407
|
+
if(!hasInput) {
|
|
408
|
+
hasInput = true
|
|
409
|
+
dataLayer.push({
|
|
410
|
+
event: "edu_page_form_input",
|
|
411
|
+
timestamp: new Date().toISOString(),
|
|
412
|
+
});
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (this.value.trim()) {
|
|
416
|
+
this.classList.remove('error');
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// 为select元素添加change事件
|
|
421
|
+
if (input.tagName === 'SELECT') {
|
|
422
|
+
input.addEventListener('change', function() {
|
|
423
|
+
if (this.value.trim()) {
|
|
424
|
+
this.classList.remove('error');
|
|
425
|
+
} else {
|
|
426
|
+
this.classList.add('error');
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
// 文件上传处理
|
|
434
|
+
const fileInput = form.querySelector('#fileUpload-{{ block.id }}');
|
|
435
|
+
const filePreview = form.querySelector('#filePreview-{{ block.id }}');
|
|
436
|
+
const fileUploadLabel = form.querySelector('.zz-edu-form-file-upload-label');
|
|
437
|
+
|
|
438
|
+
fileInput.addEventListener('change', async function(e) {
|
|
439
|
+
const file = e.target.files[0];
|
|
440
|
+
if (file) {
|
|
441
|
+
// 验证文件大小 (10MB)
|
|
442
|
+
const maxSize = 10 * 1024 * 1024; // 10MB in bytes
|
|
443
|
+
if (file.size > maxSize) {
|
|
444
|
+
zzShowToast('File size cannot exceed 10MB');
|
|
445
|
+
this.value = '';
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// 验证文件类型
|
|
450
|
+
const allowedTypes = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png'];
|
|
451
|
+
if (!allowedTypes.includes(file.type)) {
|
|
452
|
+
zzShowToast('Please upload PDF, JPG or PNG format files');
|
|
453
|
+
this.value = '';
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
// 显示文件预览
|
|
457
|
+
showFilePreview(file);
|
|
458
|
+
const fileName = await getFileMD5Name(file);
|
|
459
|
+
console.log('fileName', fileName)
|
|
460
|
+
|
|
461
|
+
httpRequest
|
|
462
|
+
.get(
|
|
463
|
+
'',
|
|
464
|
+
{},
|
|
465
|
+
{ baseUrl: 'https://aliyun-oss-sts.zerozero.cn/' }
|
|
466
|
+
)
|
|
467
|
+
.then(async (data) => {
|
|
468
|
+
if(data.StatusCode == '200') {
|
|
469
|
+
try {
|
|
470
|
+
const client = new OSS({
|
|
471
|
+
// 将<YOUR_BUCKET>设置为OSS Bucket名称。
|
|
472
|
+
bucket: "gethover-cdn-america",
|
|
473
|
+
// 将<YOUR_REGION>设置为OSS Bucket所在地域,例如region: 'oss-cn-hangzhou'。
|
|
474
|
+
region: "oss-us-east-1",
|
|
475
|
+
accessKeyId: data.AccessKeyId,
|
|
476
|
+
accessKeySecret: data.AccessKeySecret,
|
|
477
|
+
stsToken: data.SecurityToken,
|
|
478
|
+
});
|
|
479
|
+
const result = await client.put(fileName || file.name, file);
|
|
480
|
+
console.log('result---------', result)
|
|
481
|
+
if(result.url) {
|
|
482
|
+
identityDocumentUrl = result.url
|
|
483
|
+
} else {
|
|
484
|
+
removeEduVerifyFile()
|
|
485
|
+
zzShowToast('File upload failed, please try again.')
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
} catch (error) {
|
|
489
|
+
removeEduVerifyFile()
|
|
490
|
+
zzShowToast('File upload failed, please try again.')
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
} else {
|
|
494
|
+
removeEduVerifyFile()
|
|
495
|
+
zzShowToast('File upload failed, please try again.')
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
}).catch((err) => {
|
|
499
|
+
zzShowToast(EduErrorCodeConf[500].en)
|
|
500
|
+
removeEduVerifyFile()
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// 拖拽上传功能
|
|
506
|
+
fileUploadLabel.addEventListener('dragover', function(e) {
|
|
507
|
+
e.preventDefault();
|
|
508
|
+
this.classList.add('drag-over');
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
fileUploadLabel.addEventListener('dragleave', function(e) {
|
|
512
|
+
e.preventDefault();
|
|
513
|
+
this.classList.remove('drag-over');
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
fileUploadLabel.addEventListener('drop', function(e) {
|
|
517
|
+
e.preventDefault();
|
|
518
|
+
this.classList.remove('drag-over');
|
|
519
|
+
|
|
520
|
+
const files = e.dataTransfer.files;
|
|
521
|
+
if (files.length > 0) {
|
|
522
|
+
fileInput.files = files;
|
|
523
|
+
fileInput.dispatchEvent(new Event('change'));
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
function showFilePreview(file) {
|
|
528
|
+
const fileSize = (file.size / 1024 / 1024).toFixed(2);
|
|
529
|
+
const fileName = file.name;
|
|
530
|
+
|
|
531
|
+
filePreview.innerHTML = `
|
|
532
|
+
<div class="zz-edu-form-file-preview-item">
|
|
533
|
+
<div class="zz-edu-form-file-preview-info">
|
|
534
|
+
<span class="zz-edu-form-file-name">${fileName}</span>
|
|
535
|
+
<span class="zz-edu-form-file-size">${fileSize} MB</span>
|
|
536
|
+
</div>
|
|
537
|
+
<div class="zz-edu-form-file-remove-btn" onclick="removeEduVerifyFile{{ block.id }}()">
|
|
538
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
539
|
+
<circle cx="12" cy="12" r="12" fill="#DD3B46"/>
|
|
540
|
+
<path d="M8.07812 15.9609L15.9977 8.04134" stroke="white" stroke-width="1.6" stroke-linecap="round"/>
|
|
541
|
+
<path d="M8.07812 8.03906L15.9977 15.9587" stroke="white" stroke-width="1.6" stroke-linecap="round"/>
|
|
542
|
+
</svg>
|
|
543
|
+
</div>
|
|
544
|
+
</div>
|
|
545
|
+
`;
|
|
546
|
+
|
|
547
|
+
fileUploadLabel.style.display = 'none';
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// 移除文件
|
|
551
|
+
window['removeEduVerifyFile{{ block.id }}'] = function() {
|
|
552
|
+
fileInput.value = '';
|
|
553
|
+
filePreview.innerHTML = '';
|
|
554
|
+
fileUploadLabel.style.display = 'flex';
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
block.querySelector('zz-radio-tabs').addEventListener('change', (e) => {
|
|
558
|
+
verifyType = e.target.value
|
|
559
|
+
if (e.target.value === 'manual') {
|
|
560
|
+
block.querySelector('.upload-file-row').classList.remove('zz-edu-form-hidden');
|
|
561
|
+
} else {
|
|
562
|
+
block.querySelector('.upload-file-row').classList.add('zz-edu-form-hidden');
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
function getFileMD5Name(file) {
|
|
568
|
+
return new Promise((resolve, reject) => {
|
|
569
|
+
if (!file || !(file instanceof File)) {
|
|
570
|
+
resolve('');
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// 获取文件扩展名(处理无扩展名的情况)
|
|
575
|
+
const fileParts = file.name.split('.');
|
|
576
|
+
const fileExt = fileParts.length > 1 ? fileParts.pop() : '';
|
|
577
|
+
const baseName = fileParts.join('.');
|
|
578
|
+
|
|
579
|
+
const reader = new FileReader();
|
|
580
|
+
|
|
581
|
+
reader.onload = function(e) {
|
|
582
|
+
try {
|
|
583
|
+
const fileContent = e.target.result;
|
|
584
|
+
// 计算MD5哈希
|
|
585
|
+
const md5Hash = CryptoJS.MD5(CryptoJS.lib.WordArray.create(fileContent)).toString();
|
|
586
|
+
|
|
587
|
+
// 构建新文件名(保留扩展名)
|
|
588
|
+
const newFileName = fileExt ? `${md5Hash}.${fileExt}` : md5Hash;
|
|
589
|
+
|
|
590
|
+
resolve(newFileName)
|
|
591
|
+
} catch (error) {
|
|
592
|
+
resolve("");
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
reader.onerror = () => {
|
|
597
|
+
resolve('');
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
reader.readAsArrayBuffer(file);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
});
|
|
605
|
+
</script>
|
|
606
|
+
|
|
607
|
+
<style>
|
|
608
|
+
#shopify-block-{{ block.id }} {
|
|
609
|
+
{% if block.settings.background_color != blank %}
|
|
610
|
+
background-color: {{ block.settings.background_color }};
|
|
611
|
+
{% endif %}
|
|
612
|
+
width: 100%;
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.zz-edu-form-container {
|
|
617
|
+
max-width: 750px;
|
|
618
|
+
width: 100%;
|
|
619
|
+
margin: 0 auto;
|
|
620
|
+
padding-top: 30px;
|
|
621
|
+
{% comment %} padding: 40px 20px; {% endcomment %}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.zz-edu-form-form {
|
|
625
|
+
width: 100%;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.zz-edu-form-hidden {
|
|
629
|
+
display: none !important;
|
|
630
|
+
}
|
|
631
|
+
.zz-edu-form-row {
|
|
632
|
+
display: flex;
|
|
633
|
+
gap: 30px;
|
|
634
|
+
margin-bottom: 30px;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.zz-edu-form-column {
|
|
638
|
+
flex: 1;
|
|
639
|
+
}
|
|
640
|
+
.zz-edu-form-input-column {
|
|
641
|
+
flex:1;
|
|
642
|
+
{% comment %} margin-bottom: 20px; {% endcomment %}
|
|
643
|
+
}
|
|
644
|
+
.zz-edu-form-group {
|
|
645
|
+
display: flex;
|
|
646
|
+
flex-direction: column;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.zz-edu-form-label {
|
|
650
|
+
font-size: 14px;
|
|
651
|
+
font-weight: 500;
|
|
652
|
+
color: #333;
|
|
653
|
+
margin-bottom: 8px;
|
|
654
|
+
display: flex;
|
|
655
|
+
align-items: center;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.zz-edu-form-label::after {
|
|
659
|
+
content: '*';
|
|
660
|
+
color: #e74c3c;
|
|
661
|
+
margin-left: 4px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.zz-edu-form-label:has(+ input:not([required]))::after {
|
|
665
|
+
content: '';
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.zz-edu-form-name-fields {
|
|
669
|
+
display: flex;
|
|
670
|
+
gap: 30px;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.zz-edu-form-name-fields input {
|
|
674
|
+
flex: 1;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.zz-edu-form-form input[type="text"],
|
|
678
|
+
.zz-edu-form-form input[type="email"],
|
|
679
|
+
.zz-edu-form-form select {
|
|
680
|
+
padding: 12px 16px;
|
|
681
|
+
border: 1px solid #ddd;
|
|
682
|
+
border-radius: 6px;
|
|
683
|
+
font-size: 14px;
|
|
684
|
+
transition: border-color 0.3s ease;
|
|
685
|
+
background: #fff;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
.zz-edu-form-form input[type="text"]:focus,
|
|
689
|
+
.zz-edu-form-form input[type="email"]:focus,
|
|
690
|
+
.zz-edu-form-form select:focus {
|
|
691
|
+
outline: none;
|
|
692
|
+
border-color: #007bff;
|
|
693
|
+
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.zz-edu-form-form input[type="text"]::placeholder,
|
|
697
|
+
.zz-edu-form-form input[type="email"]::placeholder {
|
|
698
|
+
color: #999;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.zz-edu-form-form input.error,
|
|
702
|
+
.zz-edu-form-form select.error {
|
|
703
|
+
border-color: #e74c3c;
|
|
704
|
+
box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/* 下拉选择框样式 */
|
|
708
|
+
.zz-edu-form-form select {
|
|
709
|
+
cursor: pointer;
|
|
710
|
+
appearance: none;
|
|
711
|
+
-webkit-appearance: none;
|
|
712
|
+
-moz-appearance: none;
|
|
713
|
+
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6,9 12,15 18,9'%3e%3c/polyline%3e%3c/svg%3e");
|
|
714
|
+
background-repeat: no-repeat;
|
|
715
|
+
background-position: right 12px center;
|
|
716
|
+
background-size: 16px;
|
|
717
|
+
padding-right: 40px;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.zz-edu-form-form select option {
|
|
721
|
+
padding: 8px 12px;
|
|
722
|
+
background: #fff;
|
|
723
|
+
color: #333;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.zz-edu-form-form select option:disabled {
|
|
727
|
+
color: #999;
|
|
728
|
+
font-style: italic;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.zz-edu-form-submit {
|
|
732
|
+
display: flex;
|
|
733
|
+
justify-content: center;
|
|
734
|
+
margin-top: 20px;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.zz-edu-form-submit-btn {
|
|
738
|
+
background: #000;
|
|
739
|
+
color: white;
|
|
740
|
+
border: none;
|
|
741
|
+
border-radius: 100px;
|
|
742
|
+
font-size: 16px;
|
|
743
|
+
font-weight: 500;
|
|
744
|
+
cursor: pointer;
|
|
745
|
+
transition: background-color 0.3s ease;
|
|
746
|
+
max-width: 360px;
|
|
747
|
+
width: 100%;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.zz-edu-form-submit-btn:hover {
|
|
751
|
+
background: #333;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
/* 文件上传样式 */
|
|
757
|
+
.zz-edu-form-file-upload-container {
|
|
758
|
+
position: relative;
|
|
759
|
+
width: 100%;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
.zz-edu-form-file-input {
|
|
763
|
+
position: absolute;
|
|
764
|
+
opacity: 0;
|
|
765
|
+
width: 0;
|
|
766
|
+
height: 0;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.zz-edu-form-file-upload-label {
|
|
770
|
+
display: flex;
|
|
771
|
+
align-items: center;
|
|
772
|
+
justify-content: center;
|
|
773
|
+
width: 100%;
|
|
774
|
+
min-height: 120px;
|
|
775
|
+
border: 2px dashed #ddd;
|
|
776
|
+
border-radius: 6px;
|
|
777
|
+
cursor: pointer;
|
|
778
|
+
transition: all 0.3s ease;
|
|
779
|
+
background: #fafafa;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.zz-edu-form-file-upload-label:hover {
|
|
783
|
+
border-color: #007bff;
|
|
784
|
+
background: #f0f8ff;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.zz-edu-form-file-upload-label.drag-over {
|
|
788
|
+
border-color: #007bff;
|
|
789
|
+
background: #e6f3ff;
|
|
790
|
+
transform: scale(1.02);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.zz-edu-form-file-upload-content {
|
|
794
|
+
display: flex;
|
|
795
|
+
flex-direction: column;
|
|
796
|
+
align-items: center;
|
|
797
|
+
gap: 8px;
|
|
798
|
+
text-align: center;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.zz-edu-form-file-upload-icon {
|
|
802
|
+
color: #666;
|
|
803
|
+
width: 32px;
|
|
804
|
+
height: 32px;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.zz-edu-form-file-upload-text {
|
|
808
|
+
font-size: 16px;
|
|
809
|
+
font-weight: 500;
|
|
810
|
+
color: #333;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
.zz-edu-form-file-upload-hint {
|
|
814
|
+
font-size: 12px;
|
|
815
|
+
color: #999;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.zz-edu-form-file-preview {
|
|
819
|
+
margin-top: 12px;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.zz-edu-form-file-preview-item {
|
|
823
|
+
display: flex;
|
|
824
|
+
align-items: center;
|
|
825
|
+
justify-content: space-between;
|
|
826
|
+
padding: 12px 16px;
|
|
827
|
+
background: #f8f9fa;
|
|
828
|
+
border: 1px solid #e9ecef;
|
|
829
|
+
border-radius: 6px;
|
|
830
|
+
margin-bottom: 8px;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.zz-edu-form-file-preview-info {
|
|
834
|
+
display: flex;
|
|
835
|
+
flex-direction: column;
|
|
836
|
+
gap: 4px;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.zz-edu-form-file-name {
|
|
840
|
+
font-size: 14px;
|
|
841
|
+
font-weight: 500;
|
|
842
|
+
color: #333;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.zz-edu-form-file-size {
|
|
846
|
+
font-size: 12px;
|
|
847
|
+
color: #666;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
.zz-edu-form-file-remove-btn {
|
|
851
|
+
background: #dc3545;
|
|
852
|
+
color: white;
|
|
853
|
+
border: none;
|
|
854
|
+
border-radius: 50%;
|
|
855
|
+
width: 24px;
|
|
856
|
+
height: 24px;
|
|
857
|
+
display: flex;
|
|
858
|
+
align-items: center;
|
|
859
|
+
justify-content: center;
|
|
860
|
+
cursor: pointer;
|
|
861
|
+
font-size: 16px;
|
|
862
|
+
font-weight: bold;
|
|
863
|
+
transition: background-color 0.3s ease;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.zz-edu-form-file-remove-btn:hover {
|
|
867
|
+
background: #c82333;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.zz-edu-form-file-input.error + .zz-edu-form-file-upload-label {
|
|
871
|
+
border-color: #e74c3c;
|
|
872
|
+
background: #fff5f5;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/* 响应式设计 */
|
|
876
|
+
@media (max-width: 768px) {
|
|
877
|
+
.zz-edu-form-row {
|
|
878
|
+
flex-direction: column;
|
|
879
|
+
gap: 20px;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.zz-edu-form-name-fields {
|
|
883
|
+
flex-direction: column;
|
|
884
|
+
gap: 12px;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.zz-edu-form-file-upload-label {
|
|
888
|
+
min-height: 100px;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.zz-edu-form-file-upload-text {
|
|
892
|
+
font-size: 14px;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
</style>
|