311 lines
11 KiB
Python
311 lines
11 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
出国申请附件功能诊断脚本
|
||
用于测试附件接口和排查附件内容不显示的问题
|
||
"""
|
||
|
||
import requests
|
||
import json
|
||
import sys
|
||
from datetime import datetime
|
||
from Crypto.Cipher import AES, PKCS1_v1_5
|
||
from Crypto.PublicKey import RSA
|
||
from Crypto.Random import get_random_bytes
|
||
import base64
|
||
import hashlib
|
||
|
||
# ==================== 配置区 ====================
|
||
BASE_URL = "http://localhost:8080"
|
||
USERNAME = "admin" # 请修改为实际用户名
|
||
PASSWORD = "admin123" # 请修改为实际密码
|
||
|
||
# RSA公钥(需要从后端获取)
|
||
PUBLIC_KEY = """-----BEGIN PUBLIC KEY-----
|
||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpSA3zw+7sCf6M9yZzH4p4V4i/
|
||
ktlKPMwReLYQz0MdIj7v0xnP9h/EhGClQKJzU6EZNx8ZX8P2xVLIVMqD8pqKXLxX
|
||
j6SLvSKJKvFPPCF7P3rKqW8Y4aNwXZvFKQXlWUmE5lEJpH6P8RqYXZ0XHQZ1iyKK
|
||
CqMZXGLH1Q0PJKWmDQIDAQAB
|
||
-----END PUBLIC KEY-----"""
|
||
|
||
# ==================== 加密工具函数 ====================
|
||
|
||
def generate_aes_key():
|
||
"""生成AES密钥"""
|
||
return get_random_bytes(16)
|
||
|
||
def aes_encrypt(data, key):
|
||
"""AES加密"""
|
||
cipher = AES.new(key, AES.MODE_ECB)
|
||
# PKCS7 padding
|
||
padding_length = 16 - len(data) % 16
|
||
padded_data = data + chr(padding_length) * padding_length
|
||
encrypted = cipher.encrypt(padded_data.encode('utf-8'))
|
||
return base64.b64encode(encrypted).decode('utf-8')
|
||
|
||
def rsa_encrypt(data, public_key):
|
||
"""RSA加密"""
|
||
rsa_key = RSA.import_key(public_key)
|
||
cipher = PKCS1_v1_5.new(rsa_key)
|
||
encrypted = cipher.encrypt(data)
|
||
return base64.b64encode(encrypted).decode('utf-8')
|
||
|
||
# ==================== API请求函数 ====================
|
||
|
||
class APIClient:
|
||
def __init__(self, base_url):
|
||
self.base_url = base_url
|
||
self.token = None
|
||
self.headers = {
|
||
'Content-Type': 'application/json',
|
||
'clientid': 'e5cd7e4891bf95d1d19206ce24a7b32e',
|
||
'referer': 'http://localhost'
|
||
}
|
||
|
||
def login(self, username, password):
|
||
"""登录获取token"""
|
||
print("=" * 60)
|
||
print("【步骤1】用户登录")
|
||
print("=" * 60)
|
||
|
||
try:
|
||
# 生成AES密钥
|
||
aes_key = generate_aes_key()
|
||
aes_key_str = base64.b64encode(aes_key).decode('utf-8')
|
||
|
||
# AES加密用户名和密码
|
||
encrypted_username = aes_encrypt(username, aes_key)
|
||
encrypted_password = aes_encrypt(password, aes_key)
|
||
|
||
# RSA加密AES密钥
|
||
encrypted_aes_key = rsa_encrypt(aes_key, PUBLIC_KEY)
|
||
|
||
# 构建登录请求
|
||
login_data = {
|
||
"username": encrypted_username,
|
||
"password": encrypted_password,
|
||
"key": encrypted_aes_key,
|
||
"code": "",
|
||
"uuid": ""
|
||
}
|
||
|
||
print(f"请求URL: {self.base_url}/auth/login")
|
||
print(f"用户名: {username}")
|
||
|
||
response = requests.post(
|
||
f"{self.base_url}/auth/login",
|
||
headers=self.headers,
|
||
json=login_data
|
||
)
|
||
|
||
result = response.json()
|
||
print(f"响应状态码: {response.status_code}")
|
||
print(f"响应内容: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||
|
||
if result.get('code') == 200 and 'data' in result:
|
||
self.token = result['data'].get('access_token')
|
||
self.headers['Authorization'] = f"Bearer {self.token}"
|
||
print(f"✅ 登录成功!Token: {self.token[:50]}...")
|
||
return True
|
||
else:
|
||
print(f"❌ 登录失败: {result.get('msg', '未知错误')}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ 登录异常: {str(e)}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def get(self, url, params=None):
|
||
"""发送GET请求"""
|
||
try:
|
||
response = requests.get(
|
||
f"{self.base_url}{url}",
|
||
headers=self.headers,
|
||
params=params
|
||
)
|
||
return response.json()
|
||
except Exception as e:
|
||
print(f"❌ 请求异常: {str(e)}")
|
||
return None
|
||
|
||
def post(self, url, data=None):
|
||
"""发送POST请求"""
|
||
try:
|
||
response = requests.post(
|
||
f"{self.base_url}{url}",
|
||
headers=self.headers,
|
||
json=data
|
||
)
|
||
return response.json()
|
||
except Exception as e:
|
||
print(f"❌ 请求异常: {str(e)}")
|
||
return None
|
||
|
||
# ==================== 测试函数 ====================
|
||
|
||
def test_overseas_attachment(client):
|
||
"""测试出国申请附件功能"""
|
||
|
||
print("\n" + "=" * 60)
|
||
print("【步骤2】查询出国申请列表")
|
||
print("=" * 60)
|
||
|
||
# 查询申请列表
|
||
result = client.get("/rs/overseas/application/list", {
|
||
"pageNum": 1,
|
||
"pageSize": 10
|
||
})
|
||
|
||
if not result or result.get('code') != 200:
|
||
print(f"❌ 查询申请列表失败: {result.get('msg') if result else '请求失败'}")
|
||
return
|
||
|
||
rows = result.get('rows', [])
|
||
if not rows:
|
||
print("❌ 没有找到任何出国申请记录")
|
||
print("💡 建议:请先创建一条出国申请记录")
|
||
return
|
||
|
||
print(f"✅ 找到 {len(rows)} 条申请记录")
|
||
|
||
# 显示前5条记录
|
||
print("\n申请记录列表(前5条):")
|
||
for i, app in enumerate(rows[:5], 1):
|
||
print(f"{i}. ID={app.get('applicationId')}, "
|
||
f"申请人={app.get('applicantName')}, "
|
||
f"目的地={app.get('destination')}, "
|
||
f"状态={app.get('statusText')}")
|
||
|
||
# 选择第一条记录进行测试
|
||
test_application = rows[0]
|
||
application_id = test_application.get('applicationId')
|
||
|
||
print("\n" + "=" * 60)
|
||
print(f"【步骤3】查询申请详情(ID: {application_id})")
|
||
print("=" * 60)
|
||
|
||
detail_result = client.get(f"/rs/overseas/application/detail/{application_id}")
|
||
|
||
if not detail_result or detail_result.get('code') != 200:
|
||
print(f"❌ 查询申请详情失败: {detail_result.get('msg') if detail_result else '请求失败'}")
|
||
return
|
||
|
||
detail_data = detail_result.get('data', {})
|
||
print(f"✅ 申请详情查询成功")
|
||
print(f"申请人: {detail_data.get('applicantName')}")
|
||
print(f"目的地: {detail_data.get('destination')}")
|
||
print(f"开始日期: {detail_data.get('startDate')}")
|
||
print(f"结束日期: {detail_data.get('endDate')}")
|
||
|
||
print("\n" + "=" * 60)
|
||
print(f"【步骤4】查询附件列表(申请ID: {application_id})")
|
||
print("=" * 60)
|
||
|
||
attachment_result = client.get(f"/rs/overseas/attachment/list/{application_id}")
|
||
|
||
print(f"请求URL: {BASE_URL}/rs/overseas/attachment/list/{application_id}")
|
||
print(f"请求头: {json.dumps({k: v[:50] + '...' if len(v) > 50 else v for k, v in client.headers.items()}, ensure_ascii=False, indent=2)}")
|
||
|
||
if not attachment_result:
|
||
print("❌ 附件接口请求失败")
|
||
return
|
||
|
||
print(f"\n响应内容:")
|
||
print(json.dumps(attachment_result, ensure_ascii=False, indent=2))
|
||
|
||
if attachment_result.get('code') != 200:
|
||
print(f"\n❌ 查询附件列表失败")
|
||
print(f"错误代码: {attachment_result.get('code')}")
|
||
print(f"错误信息: {attachment_result.get('msg')}")
|
||
|
||
# 检查是否是权限问题
|
||
if attachment_result.get('code') in [401, 403]:
|
||
print("\n⚠️ 这是权限问题!")
|
||
print("请检查以下几点:")
|
||
print("1. 当前用户是否有 'rs:overseas:query' 权限")
|
||
print("2. 菜单权限配置是否正确")
|
||
print("3. 角色权限是否已授予")
|
||
|
||
return
|
||
|
||
attachment_list = attachment_result.get('data', [])
|
||
|
||
print(f"\n✅ 附件列表查询成功")
|
||
print(f"附件数量: {len(attachment_list)}")
|
||
|
||
if not attachment_list:
|
||
print("\n⚠️ 该申请暂无附件")
|
||
print("💡 建议:")
|
||
print("1. 在前端点击'添加附件'按钮上传附件")
|
||
print("2. 或使用API直接上传附件进行测试")
|
||
else:
|
||
print("\n附件列表详情:")
|
||
print("-" * 100)
|
||
for i, attachment in enumerate(attachment_list, 1):
|
||
print(f"\n附件 {i}:")
|
||
print(f" - 附件ID: {attachment.get('attachmentId')}")
|
||
print(f" - 附件标题: {attachment.get('attachmentTitle')}")
|
||
print(f" - 附件说明: {attachment.get('attachmentContent', '无')}")
|
||
print(f" - 原始文件名: {attachment.get('fileOriginalName')}")
|
||
print(f" - 文件名: {attachment.get('fileName')}")
|
||
print(f" - 文件路径: {attachment.get('filePath')}")
|
||
print(f" - 文件大小: {attachment.get('fileSizeFormatted', attachment.get('fileSize'))}")
|
||
print(f" - MIME类型: {attachment.get('mimeType', '未知')}")
|
||
print(f" - 上传时间: {attachment.get('uploadTime', '未知')}")
|
||
print(f" - 上传人: {attachment.get('uploadUserName', '未知')}")
|
||
|
||
print("\n" + "=" * 60)
|
||
print("【诊断结果】")
|
||
print("=" * 60)
|
||
|
||
if not attachment_list:
|
||
print("🔍 问题原因分析:")
|
||
print("1. 该申请确实没有附件数据")
|
||
print("2. 附件接口返回正常,但数据为空")
|
||
print("\n🔧 解决方案:")
|
||
print("1. 请在前端点击'添加附件'按钮上传附件")
|
||
print("2. 确认附件上传后,再次查看详情")
|
||
else:
|
||
print("✅ 附件数据存在且接口返回正常")
|
||
print("\n🔍 如果前端仍然看不到附件,可能的原因:")
|
||
print("1. 前端组件的数据绑定问题")
|
||
print("2. Vue响应式数据未更新")
|
||
print("3. 条件渲染判断错误")
|
||
print("4. 浏览器控制台可能有JavaScript错误")
|
||
print("\n🔧 建议检查:")
|
||
print("1. 打开浏览器F12开发者工具")
|
||
print("2. 查看Console标签页是否有错误")
|
||
print("3. 查看Network标签页确认API请求是否成功")
|
||
print("4. 检查Vue Devtools中viewAttachmentList的值")
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("=" * 60)
|
||
print("出国申请附件功能诊断脚本")
|
||
print("=" * 60)
|
||
print(f"基础URL: {BASE_URL}")
|
||
print(f"用户名: {USERNAME}")
|
||
print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||
print()
|
||
|
||
# 创建API客户端
|
||
client = APIClient(BASE_URL)
|
||
|
||
# 登录
|
||
if not client.login(USERNAME, PASSWORD):
|
||
print("\n❌ 登录失败,无法继续测试")
|
||
sys.exit(1)
|
||
|
||
# 测试附件功能
|
||
test_overseas_attachment(client)
|
||
|
||
print("\n" + "=" * 60)
|
||
print("诊断完成")
|
||
print("=" * 60)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|