info 本文章代码均为AI生成,请注意仔细甄别!
使用模型:海螺AI,deepseek R1;Qwen2.5-Max

近期,DeepSeek的热度颇高,我也萌生了借助它开发项目的想法。
此前,我曾关注过一位B站UP主(链接见下)分享的通过二维码传输图片或文件的代码,便计划复刻类似功能。由于自身编程能力有限,我决定尝试通过AI辅助完成这一项目。

我初期使用了deepseek推出的R1模型,通过对我所述的进行编程,但是…这个…它现在被攻击,服务器十分不稳定,处于第一句可以答但第二句就“服务器繁忙,请稍后重试”的状态…所以我只能先退一步,让“海螺AI”生成这个代码。

如下是我写的大纲,基本思路是对的。

查看大纲

##工作原理

输出端用户上传文件,网站拆分内容为X份,将内容放入二维码,通过屏幕展示出来,输入端用户进行扫描,将若干二维码合并成原内容,形成文件。

##具体实现步骤

这里需提前说明,X的值取决于用户选择输出多大(Z)的二维码以及转化后的内容大小。M的值需要用户输入。
文件不限格式,但如果是图片和txt文件需要格外注意。
输出端步骤

  1. 输出端用户需要上传文件,可上传多个文件(最多25个),网站先对源文件分析得到SHA-256,大小。
  2. 网站将文件转换成Base64代码 ,连同,文件名称,大小,类型一起(这三个放在代码最前面),将它们合理拆分,得到X个组块。但请注意,拆分后需要再每个组块后面都加入英文半角符号“-” 和字母(如果是多个文件,按照文件大小排序由AY)和数字Y(用于判断拆分顺序)(1X)。例如A1,A2,A3,B1,B2,C1,C2,C3,C4。再加入SHA-256,最后加入“-”和组块数量X。
  3. 每个组块需要加密,采用椭圆曲线加密(ECC)(这里使用椭圆曲线 secp256r1)的形式。
    其中:
    a. 程序内包含有25个私钥,25个临时私钥。(内容已附在Excel,一一对应。)
    b. 根据ECC的规则,将临时公钥随机地放置在每个组块开头(在临时公钥后加上英文半角符号“-”)以供识别。
    c. 加密的时候除了临时公钥和第一个“-”不要加密,其他的均需要加密。
    现在,举个例子。(还没有加密)(这里以文件处理后只有一个组块为例)
    030c6208f6b0bf5641766b61e0bea555cd8ef5ab8b9e94f5cb79957096eebffb9c-Y2VzaGkxMjNoYWhh-A1-C6322C7382AA4329A29347AEF4D72EF85FD48B77896820AB9C3F51450B28C2BA-1
    其中,“030c6208f6b0bf5641766b61e0bea555cd8ef5ab8b9e94f5cb79957096eebffb9c”是临时公钥(这个不要加密),“Y2VzaGkxMjNoYWhh”是Base64值,“A1”对应“字母和数字Y”,“C6322C7382AA4329A29347AEF4D72EF85FD48B77896820AB9C3F51450B28C2BA”对应源文件SHA256值,“1”对应组块数量为1。英文半角符号“-”不可省略。
  4. 需要将这X组块塞到X个大小为Z*Z的二维码中。 输出端需要将X个二维码以幻灯片的形式每秒M个二维码的速度快速显示在网页中央,便于输入端扫描。

##输出端步骤
1. 输入端需要调用摄像头权限,不断扫描输出端的二维码直到所有内容均已被扫描识别。输入端需要将已扫描和未扫描的二维码编号放在扫描摄像头窗口的下面,便于用户判断。
2. 输入端的扫描摄像头应标识扫描进度以及扫描速度(以Kb/s的形式展现)。
3. 获取到每个二维码后采用ECC的解密方法将原来的加密内容进行解密,再由顺序拼回去,再由Base64得到源文件。
其中需要注意的地方有以下几点
a. 解密时源文件Base64内容只是第一个“-”到第二个“-”之间的数据,其他的仅供程序判断。
b. 程序需要根据临时公钥和私钥计算共享密钥,恢复消息点,解码。
c. 解密时不要连带临时秘钥一起解密,只有第一个“-”之后(不含)的需要解密。
4. 扫描结束后应提示用户是否储存(在此之前应存入缓存中)。

可能有表述不清楚的地方,不过也就那样了,能理解就可以吧(我觉得应该...没问题,如果硬要质疑的话请往下看)

我采用了python+浏览器的形式来处理这个问题,不过…好像和他的差了好多…
然后这是它生成的最终代码(只有输出端)

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
import binascii
import os

def generate_public_key(private_key_hex: str) -> str:
"""
根据给定的私钥(十六进制字符串)生成对应的公钥(压缩格式的十六进制字符串)。

:param private_key_hex: 私钥,十六进制字符串
:return: 公钥,压缩格式的十六进制字符串或错误信息
"""
try:
# 将十六进制字符串转换为字节
private_key_bytes = binascii.unhexlify(private_key_hex)

# 加载私钥
private_key = ec.derive_private_key(
int.from_bytes(private_key_bytes, byteorder='big'),
ec.SECP256R1()
)

# 获取公钥
public_key = private_key.public_key()

# 序列化公钥为压缩格式(X9.62格式)
public_key_bytes = public_key.public_bytes(
encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.CompressedPoint
)

# 将公钥转换为十六进制字符串
public_key_hex = binascii.hexlify(public_key_bytes).decode()

return public_key_hex
except Exception as e:
return f"Error: {str(e)}"

def batch_convert(source_path: str, target_path: str):
"""
批量转换私钥为公钥。

:param source_path: 源TXT文件路径
:param target_path: 目标TXT文件路径
"""
try:
with open(source_path, 'r') as src_file, open(target_path, 'w') as tgt_file:
line_num = 0
for line in src_file:
line_num += 1
# 去除空白字符
private_key = line.strip()

# 验证私钥长度
if len(private_key) != 64:
error_msg = f"Line {line_num}: 私钥长度应为64个十六进制字符(256位)。"
tgt_file.write(f"{error_msg}\n")
continue

# 生成公钥
public_key = generate_public_key(private_key)

# 写入目标文件
tgt_file.write(f"{public_key}\n")

print(f"转换完成。输出文件位于:{target_path}")
except FileNotFoundError:
print(f"错误:文件未找到。请检查路径:{source_path}")
except Exception as e:
print(f"发生错误:{str(e)}")

def main():
print("ECC公钥批量转换器(基于secp256r1)")
source_path = input("请输入源TXT文件的本地路径(例如:C:/keys/source.txt):\n")

# 检查文件是否存在
if not os.path.isfile(source_path):
print(f"错误:文件不存在。请检查路径:{source_path}")
return

# 生成目标文件路径
directory, filename = os.path.split(source_path)
filename_no_ext, ext = os.path.splitext(filename)
target_filename = f"{filename_no_ext}_public_keys{ext}"
target_path = os.path.join(directory, target_filename)

# 开始转换
batch_convert(source_path, target_path)

if __name__ == "__main__":
main()

虽然有那么点意思,但是还是有点不尽人意…于是我就暂置了几天(4天),直到通义千问Qwen的出现,算是救了一场。

听说这个好用,我就试了试(免费哈)(目前),发现确实有意思!我让它生成了代码,响应迅速,很不错(没有打广告,实事求是而已…)。我通过一步一步引导它,没想到还真就像模像样的搞出来一个版本出来,具体如下。
首先是它的框架:
project/
├── app.py
├── key.xlsx
├── templates/
│ └── index.html
├── static/
│ └── qrs/
其中,这个“app.py”作为主代码,集成了输入和输出端,可以供用户选择功能。key.xlsx是存放私钥和公钥的地方(含临时),有意思的是,这个东西我没有选择隐藏加密(我不会…)。qrs是存放二维码的地方。index.html使用了浏览器,用于上传和展示二维码。
下面是源码(最后会给你,不用复制了):

源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
import os
import sys
import shutil
import base64
import hashlib
import pandas as pd
from Cryptodome.PublicKey import ECC
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad, unpad
import qrcode
import io
import cv2
import numpy as np
from flask import Flask, request, jsonify, render_template_string, send_from_directory

# ============================== 配置根目录 ==============================
ROOT_DIR = r"C:\Users\lenovo\Documents\qrs"

# 确保根目录及其子目录存在
def ensure_root_directory():
"""
确保根目录及其子目录存在。
如果不存在,则创建它们。
"""
if not os.path.exists(ROOT_DIR):
os.makedirs(ROOT_DIR)
print(f"已创建根目录: {ROOT_DIR}")

# 确保子目录存在
subdirs = ["uploads", "qrs", "templates", "static"]
for subdir in subdirs:
subdir_path = os.path.join(ROOT_DIR, subdir)
if not os.path.exists(subdir_path):
os.makedirs(subdir_path)
print(f"已创建子目录: {subdir_path}")

# 获取资源文件的路径
def resource_path(relative_path):
"""
动态获取资源文件的路径。
- 在开发环境中,返回相对路径。
- 在打包后的环境中,返回 PyInstaller 解压路径。
"""
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)

# 解压依赖文件到目标目录
def extract_dependencies():
"""
将依赖文件解压到目标目录。
如果文件已存在,则不会重复解压。
"""
dependencies = {
"key.xlsx": os.path.join(ROOT_DIR, "key.xlsx"),
"templates/index.html": os.path.join(ROOT_DIR, "templates/index.html"),
}

for src, dst in dependencies.items():
if not os.path.exists(dst):
src_path = resource_path(src)
shutil.copy(src_path, dst)
print(f"已解压文件: {src} -> {dst}")

# 初始化根目录和依赖文件
ensure_root_directory()
extract_dependencies()

# 示例:加载 key.xlsx 文件
key_excel_path = os.path.join(ROOT_DIR, "key.xlsx")

# 示例:加载模板文件
template_html_path = os.path.join(ROOT_DIR, "templates/index.html")

# 初始化 Flask 应用
app = Flask(__name__, static_folder=resource_path("static"))

# ============================== 公共函数 ==============================

def load_keys_from_excel(file_path):
"""
从 Excel 文件中加载私钥和临时私钥。
返回两个列表:私钥和临时私钥。
"""
if not os.path.exists(file_path):
raise FileNotFoundError("Excel file not found")
df = pd.read_excel(file_path)
private_keys = df['私钥d'].tolist()
temp_private_keys = df['临时私钥r'].tolist()
return private_keys, temp_private_keys

def encrypt_data_aes(data, shared_key):
"""
使用 AES 对称加密加密数据。
返回加密后的数据(IV + 密文)。
"""
key = shared_key[:32] # 截取32字节作为AES密钥
cipher = AES.new(key, AES.MODE_CBC)
ct_bytes = cipher.encrypt(pad(data.encode('utf-8'), AES.block_size))
iv = cipher.iv
return iv.hex() + ct_bytes.hex() # 返回IV和加密数据的十六进制表示

def decrypt_data_aes(encrypted_data, shared_key):
"""
使用 AES 对称加密解密数据。
返回解密后的原始数据。
"""
key = shared_key[:32] # 截取32字节作为AES密钥
iv = bytes.fromhex(encrypted_data[:32]) # 提取IV
ct = bytes.fromhex(encrypted_data[32:]) # 提取加密数据
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(ct), AES.block_size)
return decrypted_data.decode('utf-8')

def compute_shared_key(temp_public_key, private_key):
"""
计算共享密钥。
使用 ECC 的规则,基于临时公钥和私钥计算共享密钥。
"""
ecc_key = ECC.construct(curve='secp256r1', d=int(private_key, 16))
temp_pub_key = ECC.import_key(temp_public_key)
shared_key = ecc_key.d * temp_pub_key.pointQ # 共享密钥
compressed_shared_key = hashlib.sha256(str(shared_key.x).encode('utf-8')).digest() # 压缩共享密钥
return compressed_shared_key

# ============================== 输出端功能 ==============================

def analyze_and_convert(file_path):
"""
分析文件并将其转换为 Base64 格式。
返回文件的 SHA256、大小、类型和 Base64 内容。
"""
try:
with open(file_path, 'rb') as f:
content = f.read()
sha256_hash = hashlib.sha256(content).hexdigest()
file_size = os.path.getsize(file_path)
file_type = file_path.split('.')[-1]
base64_content = base64.b64encode(content).decode('utf-8')
return sha256_hash, file_size, file_type, base64_content
except Exception as e:
raise ValueError(f"File analysis failed: {str(e)}")

def split_and_encrypt(data, private_key, temp_private_key, chunk_size=1000):
"""
将数据分块并加密。
每个组块包含临时公钥、加密数据、字母编号、数字编号、SHA256校验值和组块数量。
返回加密后的组块列表。
"""
chunks = [data[i:i + chunk_size] for i in range(0, len(data), chunk_size)]
encrypted_chunks = []
try:
# ECC 密钥生成
ecc_key = ECC.construct(curve='secp256r1', d=int(temp_private_key, 16))
public_key = ecc_key.public_key()
shared_key = int(private_key, 16) * int(ecc_key.d) # 共享密钥
compressed_shared_key = hashlib.sha256(str(shared_key).encode('utf-8')).digest() # 压缩共享密钥

for idx, chunk in enumerate(chunks):
# 使用 AES 对称加密加密数据
aes_encrypted_chunk = encrypt_data_aes(chunk, compressed_shared_key)
# 组合数据:临时公钥 + AES 加密数据 + 字母编号 + 数字编号 + SHA256校验值 + 组块数量 + 文件后缀
hex_index = f"{idx + 1:02X}" # 十六进制编号(两位)
encrypted_chunk = (
str(public_key.export_key(format='PEM')) + '-' +
aes_encrypted_chunk + '-' +
"A" + hex_index + '-' + # 字母编号(假设单个文件)
hashlib.sha256(chunk.encode('utf-8')).hexdigest() + '-' +
str(len(chunks)) + '-' +
file_type # 添加文件后缀
)
encrypted_chunks.append(encrypted_chunk)
except Exception as e:
raise ValueError(f"ECC encryption failed: {str(e)}")
return encrypted_chunks

def generate_qr_codes_in_memory(chunks, file_name):
"""
将加密后的组块生成二维码。
返回二维码的二进制数据列表。
"""
qr_images = []
file_qr_folder = os.path.join(ROOT_DIR, "qrs", file_name)
if not os.path.exists(file_qr_folder):
os.makedirs(file_qr_folder)

for idx, chunk in enumerate(chunks):
qr = qrcode.QRCode(version=1, box_size=10, border=5)
qr.add_data(chunk)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
buffer = io.BytesIO()
img.save(buffer, format="PNG")
buffer.seek(0) # 将指针重置到文件开头
qr_images.append(buffer.getvalue())

# 保存二维码到文件夹
qr_path = os.path.join(file_qr_folder, f"{file_name}_qr_{idx + 1}.png")
with open(qr_path, 'wb') as f:
f.write(buffer.getvalue())

return qr_images

@app.route('/upload', methods=['POST'])
def upload_files():
"""
处理文件上传请求。
用户上传文件后,程序会分析文件、加密内容并生成二维码。
返回 JSON 格式的响应,包含上传结果和二维码路径。
"""
try:
if 'files' not in request.files or not request.files.getlist('files'):
return jsonify({'error': 'No files uploaded'}), 400

files = request.files.getlist('files')
saved_files = []

# 加载私钥和临时私钥
excel_path = os.path.join(ROOT_DIR, "key.xlsx") # 私钥文件路径
private_keys, temp_private_keys = load_keys_from_excel(excel_path)

all_qr_paths = []

for i, file in enumerate(files):
if file.filename == '':
continue # 跳过空文件名
file_path = os.path.join(ROOT_DIR, "uploads", file.filename)
file.save(file_path)
saved_files.append(file.filename)

# 分析文件并生成二维码
sha256_hash, file_size, file_type, base64_content = analyze_and_convert(file_path)
header = f"{file_type}-{file_size}-{sha256_hash}-"
data = header + base64_content
encrypted_chunks = split_and_encrypt(data, private_keys[i], temp_private_keys[i])
qr_images = generate_qr_codes_in_memory(encrypted_chunks, file.filename)

# 保存二维码路径
file_qr_folder = os.path.join(ROOT_DIR, "qrs", file.filename)
qr_paths = [f"/static/qrs/{file.filename}/{file.filename}_qr_{j + 1}.png" for j in range(len(qr_images))]
all_qr_paths.extend(qr_paths)

return jsonify({
'message': 'Files uploaded successfully!',
'files': saved_files,
'qr_paths': all_qr_paths
})
except Exception as e:
return jsonify({'error': f'Server error: {str(e)}'}), 500

@app.route('/')
def index():
"""
渲染首页。
"""
return render_template_string(open(template_html_path, 'r', encoding='utf-8').read())

# ============================== 输入端功能 ==============================

def scan_qr_code():
"""
扫描二维码。
使用 OpenCV 打开摄像头,实时扫描二维码并返回扫描到的数据。
"""
cap = cv2.VideoCapture(0) # 打开摄像头
scanned_data = []

while True:
ret, frame = cap.read()
if not ret:
print("无法读取摄像头画面")
break

# 使用 OpenCV 检测二维码
detector = cv2.QRCodeDetector()
data, bbox, _ = detector.detectAndDecode(frame)

if data:
scanned_data.append(data)
print(f"已扫描二维码: {data}")

# 显示扫描到的二维码编号
cv2.putText(frame, f"Scanned: {len(scanned_data)}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

# 显示摄像头画面
cv2.imshow("QR Code Scanner", frame)

# 按下 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break

cap.release()
cv2.destroyAllWindows()
return scanned_data

def process_scanned_data(scanned_data, private_keys):
"""
处理解密和文件还原。
根据扫描到的二维码数据,解密并拼接成原始文件。
返回还原的文件内容和文件扩展名。
"""
decrypted_chunks = {}
file_extension = None

for data in scanned_data:
parts = data.split('-')
temp_public_key = parts[0]
encrypted_chunk = parts[1]
file_info = parts[2] # 包含字母编号、SHA256 和组块数量
sha256_hash = parts[3]
total_chunks = int(parts[4])
extension = parts[5] # 文件后缀

# 确定文件后缀(仅需一次)
if not file_extension:
file_extension = extension

# 获取对应的私钥
private_key = private_keys[ord(file_info[0]) - ord('A')] # 根据字母索引获取私钥

# 计算共享密钥
shared_key = compute_shared_key(temp_public_key, private_key)

# 解密数据
decrypted_data = decrypt_data_aes(encrypted_chunk, shared_key)
decrypted_chunks[file_info] = decrypted_data

# 按顺序拼接数据
sorted_keys = sorted(decrypted_chunks.keys()) # 按文件编号排序
full_data = ''.join([decrypted_chunks[key] for key in sorted_keys])

# 还原文件
file_content = base64.b64decode(full_data)
return file_content, file_extension

def input_end_main():
"""
输入端主函数。
启动摄像头扫描二维码,并将扫描到的内容解密还原为文件。
"""
excel_path = os.path.join(ROOT_DIR, "key.xlsx") # 私钥文件路径
private_keys = load_keys_from_excel(excel_path)

print("开始扫描二维码...")
scanned_data = scan_qr_code()

if not scanned_data:
print("未扫描到任何二维码")
return

print("正在处理扫描数据...")
try:
file_content, file_extension = process_scanned_data(scanned_data, private_keys)
output_file = os.path.join(ROOT_DIR, f"output_file.{file_extension}")
with open(output_file, 'wb') as f:
f.write(file_content)
print(f"文件已保存为: {output_file}")
except Exception as e:
print(f"处理失败: {str(e)}")

# ============================== 主程序入口 ==============================

def main():
"""
主程序入口。
用户可以选择运行输出端功能或输入端功能。
"""
try:
print("请选择功能:")
print("1. 输出端功能(上传文件并生成二维码)")
print("2. 输入端功能(扫描二维码并还原文件)")
choice = input("请输入选项(1 或 2):")

if choice == '1':
print("启动 Flask 服务器...")
app.run(host='0.0.0.0', debug=False, port=8000)
elif choice == '2':
print("启动输入端功能...")
input_end_main()
else:
print("无效选项,请重新运行程序。")
except Exception as e:
print(f"程序运行失败: {str(e)}")

if __name__ == '__main__':
main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>二维码展示</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f4f4f9;
}
.upload-area {
width: 300px;
height: 200px;
border: 2px dashed #ccc;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
text-align: center;
color: #666;
cursor: pointer;
}
.upload-area:hover {
border-color: '#aaa';
}
.hidden-input {
display: none;
}
.progress-container {
margin-top: 20px;
width: 100%;
}
.progress-bar {
width: 0%;
height: 20px;
background-color: #4caf50;
transition: width 0.3s ease;
}
.status {
margin-top: 10px;
font-size: 14px;
color: #333;
}
</style>
</head>
<body>
<div class="upload-area" id="uploadArea">
<p>拖动文件到这里</p>
<p>或者</p>
<button onclick="document.getElementById('fileInput').click()">选择文件</button>
<input type="file" id="fileInput" class="hidden-input" multiple onchange="handleFiles(this.files)">
</div>

<div class="progress-container" id="progressContainer" style="display: none;">
<div class="progress-bar" id="progressBar"></div>
<div class="status" id="status">上传中...</div>
</div>

<script>
const uploadArea = document.getElementById('uploadArea');
const progressContainer = document.getElementById('progressContainer');
const progressBar = document.getElementById('progressBar');
const status = document.getElementById('status');

// 处理文件上传
function handleFiles(files) {
const formData = new FormData();
for (const file of files) {
formData.append('files', file);
}

// 显示进度条
progressContainer.style.display = 'block';

// 创建 EventSource 连接
const eventSource = new EventSource(`/upload`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: formData,
});

eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);

// 更新进度条
progressBar.style.width = `${data.progress}%`;

// 更新状态信息
status.textContent = data.message;

// 如果上传完成,关闭连接
if (data.progress === 100) {
eventSource.close();
alert('文件上传成功!');
}
};

eventSource.onerror = function(error) {
console.error('上传失败:', error);
alert('文件上传失败,请重试!');
eventSource.close();
};
}

// 拖放事件处理
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.style.borderColor = '#aaa';
});

uploadArea.addEventListener('dragleave', () => {
uploadArea.style.borderColor = '#ccc';
});

uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.style.borderColor = '#ccc';
const files = e.dataTransfer.files;
handleFiles(files);
});
</script>
</body>
</html>

事实上,这玩意是真长…
咳咳,这个代码基本上实现了我想要的功能,就是…需要优化…有点难搞。
琢磨这些代码,我不惜牺牲玩的时间,最后好像成了,但是…有一个新问题出来了!就是这个该死的“405”报错!
GET http://127.0.0.1:8000/upload 405 (METHOD NOT ALLOWED)
这就导致我无法上传文件,很奇怪,但我也不知道该怎么办,网上查的话…一点也看不懂(好笨…)。我试了试之前的代码(还没有整合的时候),发现那时候的也是这个问题,我很纳闷。所以,我会附上源码,我与AI的对话过程,还有一个二维码图片示例,你们可以自己琢磨琢磨…
最后,我还想提一嘴,盲猜有人说,为什么要用ECC加密…我乐意!不过这个对现在的Bug好像没影响。
最后…的最后,附上文件(密码GKZJ):

点击此处查看

最后...最后的最后,这篇文章应该是我在高考前的最后一篇文章了,再见!