| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>售后归档数据连接测试</title>
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
-
- body {
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- min-height: 100vh;
- padding: 20px;
- }
-
- .container {
- max-width: 1200px;
- margin: 0 auto;
- }
-
- .header {
- background: white;
- padding: 30px;
- border-radius: 12px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
- margin-bottom: 20px;
- }
-
- .header h1 {
- color: #667eea;
- margin-bottom: 10px;
- }
-
- .test-section {
- background: white;
- padding: 25px;
- border-radius: 12px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
- margin-bottom: 20px;
- }
-
- .test-section h2 {
- color: #333;
- margin-bottom: 15px;
- padding-bottom: 10px;
- border-bottom: 2px solid #667eea;
- }
-
- .button-group {
- display: flex;
- gap: 10px;
- margin-bottom: 20px;
- flex-wrap: wrap;
- }
-
- button {
- padding: 12px 24px;
- border: none;
- border-radius: 8px;
- background: #667eea;
- color: white;
- font-size: 14px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s;
- }
-
- button:hover {
- background: #5568d3;
- transform: translateY(-2px);
- box-shadow: 0 4px 8px rgba(102, 126, 234, 0.3);
- }
-
- button:disabled {
- background: #ccc;
- cursor: not-allowed;
- transform: none;
- }
-
- .log {
- background: #f8f9fa;
- border: 1px solid #dee2e6;
- border-radius: 8px;
- padding: 15px;
- font-family: 'Courier New', monospace;
- font-size: 13px;
- line-height: 1.6;
- max-height: 400px;
- overflow-y: auto;
- white-space: pre-wrap;
- word-wrap: break-word;
- }
-
- .log-entry {
- margin-bottom: 5px;
- }
-
- .log-success {
- color: #28a745;
- }
-
- .log-error {
- color: #dc3545;
- }
-
- .log-info {
- color: #17a2b8;
- }
-
- .log-warning {
- color: #ffc107;
- }
-
- .stats {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 15px;
- margin: 20px 0;
- }
-
- .stat-card {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- padding: 20px;
- border-radius: 8px;
- text-align: center;
- }
-
- .stat-card h3 {
- font-size: 14px;
- margin-bottom: 10px;
- opacity: 0.9;
- }
-
- .stat-card .value {
- font-size: 32px;
- font-weight: bold;
- }
-
- .file-upload {
- border: 2px dashed #667eea;
- border-radius: 8px;
- padding: 30px;
- text-align: center;
- cursor: pointer;
- transition: all 0.3s;
- margin: 20px 0;
- }
-
- .file-upload:hover {
- background: #f8f9fa;
- border-color: #5568d3;
- }
-
- .file-upload input {
- display: none;
- }
- </style>
- </head>
- <body>
- <div class="container">
- <div class="header">
- <h1>🔧 售后归档数据连接测试</h1>
- <p>测试项目ID: <strong>yjVLy8KxyG</strong></p>
- <p>测试公司ID: <strong>cDL6R1hgSi</strong></p>
- </div>
-
- <!-- 1. ProjectPayment测试 -->
- <div class="test-section">
- <h2>💰 ProjectPayment表测试</h2>
- <div class="button-group">
- <button onclick="testProjectPayment()">查询付款记录</button>
- <button onclick="createTestPayment()">创建测试数据</button>
- <button onclick="clearPayments()">清空测试数据</button>
- </div>
- <div class="stats" id="payment-stats"></div>
- <div class="log" id="payment-log"></div>
- </div>
-
- <!-- 2. 文件上传测试 -->
- <div class="test-section">
- <h2>📤 文件上传测试(NovaStorage)</h2>
- <div class="file-upload" onclick="document.getElementById('fileInput').click()">
- <input type="file" id="fileInput" accept="image/*" onchange="uploadFile(event)">
- <p>📁 点击选择图片文件</p>
- <p style="font-size: 12px; color: #666; margin-top: 10px;">支持 JPG, PNG, GIF等格式</p>
- </div>
- <div class="log" id="upload-log"></div>
- </div>
-
- <!-- 3. AI识别测试 -->
- <div class="test-section">
- <h2>🤖 AI凭证识别测试</h2>
- <div class="button-group">
- <button onclick="testAIRecognition()">测试AI识别</button>
- </div>
- <div class="log" id="ai-log"></div>
- </div>
-
- <!-- 4. 完整流程测试 -->
- <div class="test-section">
- <h2>🔄 完整流程测试</h2>
- <div class="button-group">
- <button onclick="testFullFlow()">测试完整流程</button>
- <button onclick="clearAllLogs()">清空日志</button>
- </div>
- <div class="log" id="flow-log"></div>
- </div>
- </div>
- <script type="module">
- import { FmodeParse } from 'https://unpkg.com/fmode-ng@latest/dist/parse/index.mjs';
- import { NovaStorage } from 'https://unpkg.com/fmode-ng@latest/dist/core/index.mjs';
- import { completionJSON } from 'https://unpkg.com/fmode-ng@latest/dist/core/agent/chat/completion.mjs';
-
- const Parse = FmodeParse.with('nova');
-
- const PROJECT_ID = 'yjVLy8KxyG';
- const COMPANY_ID = 'cDL6R1hgSi';
-
- // 日志函数
- window.log = function(elementId, message, type = 'info') {
- const logElement = document.getElementById(elementId);
- const timestamp = new Date().toLocaleTimeString();
- const className = `log-${type}`;
- const icon = {
- success: '✅',
- error: '❌',
- info: 'ℹ️',
- warning: '⚠️'
- }[type] || '';
-
- const entry = document.createElement('div');
- entry.className = `log-entry ${className}`;
- entry.textContent = `[${timestamp}] ${icon} ${message}`;
- logElement.appendChild(entry);
- logElement.scrollTop = logElement.scrollHeight;
- };
-
- // 清空日志
- window.clearAllLogs = function() {
- const logs = document.querySelectorAll('.log');
- logs.forEach(log => log.innerHTML = '');
- };
-
- // 更新统计卡片
- function updateStats(stats) {
- const statsElement = document.getElementById('payment-stats');
- statsElement.innerHTML = `
- <div class="stat-card">
- <h3>总金额</h3>
- <div class="value">¥${stats.totalAmount || 0}</div>
- </div>
- <div class="stat-card">
- <h3>已支付</h3>
- <div class="value">¥${stats.paidAmount || 0}</div>
- </div>
- <div class="stat-card">
- <h3>待支付</h3>
- <div class="value">¥${stats.remainingAmount || 0}</div>
- </div>
- <div class="stat-card">
- <h3>尾款</h3>
- <div class="value">¥${stats.finalAmount || 0}</div>
- </div>
- `;
- }
-
- // 1. 测试ProjectPayment查询
- window.testProjectPayment = async function() {
- log('payment-log', '开始查询ProjectPayment表...', 'info');
-
- try {
- const query = new Parse.Query('ProjectPayment');
- query.equalTo('project', {
- __type: 'Pointer',
- className: 'Project',
- objectId: PROJECT_ID
- });
- query.include('voucherFile', 'product', 'paidBy');
- query.descending('createdAt');
-
- const payments = await query.find();
- log('payment-log', `找到 ${payments.length} 条付款记录`, 'success');
-
- let totalAmount = 0;
- let paidAmount = 0;
- let finalAmount = 0;
-
- for (const payment of payments) {
- const amount = payment.get('amount') || 0;
- const type = payment.get('type');
- const status = payment.get('status');
-
- log('payment-log', ` ${type}: ¥${amount} (${status})`, 'info');
-
- totalAmount += amount;
- if (status === 'paid') {
- paidAmount += amount;
- }
- if (type === 'final') {
- finalAmount += amount;
- }
- }
-
- const stats = {
- totalAmount,
- paidAmount,
- remainingAmount: totalAmount - paidAmount,
- finalAmount
- };
-
- updateStats(stats);
- log('payment-log', `统计完成: 总${totalAmount}, 已付${paidAmount}, 待付${totalAmount - paidAmount}`, 'success');
-
- if (payments.length === 0) {
- log('payment-log', '⚠️ 没有找到付款记录,请创建测试数据', 'warning');
- }
-
- } catch (error) {
- log('payment-log', `查询失败: ${error.message}`, 'error');
- console.error(error);
- }
- };
-
- // 2. 创建测试付款数据
- window.createTestPayment = async function() {
- log('payment-log', '开始创建测试数据...', 'info');
-
- try {
- // 创建预付款
- const advance = new Parse.Object('ProjectPayment');
- advance.set('project', { __type: 'Pointer', className: 'Project', objectId: PROJECT_ID });
- advance.set('company', { __type: 'Pointer', className: 'Company', objectId: COMPANY_ID });
- advance.set('type', 'advance');
- advance.set('stage', 'order');
- advance.set('amount', 40000);
- advance.set('method', 'bank_transfer');
- advance.set('status', 'paid');
- advance.set('paymentDate', new Date());
- advance.set('currency', 'CNY');
- advance.set('description', '项目预付款');
- await advance.save();
- log('payment-log', '✅ 创建预付款: ¥40000', 'success');
-
- // 创建尾款
- const final = new Parse.Object('ProjectPayment');
- final.set('project', { __type: 'Pointer', className: 'Project', objectId: PROJECT_ID });
- final.set('company', { __type: 'Pointer', className: 'Company', objectId: COMPANY_ID });
- final.set('type', 'final');
- final.set('stage', 'aftercare');
- final.set('amount', 80000);
- final.set('method', 'bank_transfer');
- final.set('status', 'pending');
- final.set('currency', 'CNY');
- final.set('description', '项目尾款');
- const dueDate = new Date();
- dueDate.setDate(dueDate.getDate() + 30);
- final.set('dueDate', dueDate);
- await final.save();
- log('payment-log', '✅ 创建尾款: ¥80000 (待支付)', 'success');
-
- log('payment-log', '✅ 测试数据创建成功!', 'success');
-
- // 重新查询
- await testProjectPayment();
-
- } catch (error) {
- log('payment-log', `创建失败: ${error.message}`, 'error');
- console.error(error);
- }
- };
-
- // 3. 清空测试数据
- window.clearPayments = async function() {
- log('payment-log', '开始清空测试数据...', 'info');
-
- try {
- const query = new Parse.Query('ProjectPayment');
- query.equalTo('project', {
- __type: 'Pointer',
- className: 'Project',
- objectId: PROJECT_ID
- });
-
- const payments = await query.find();
- log('payment-log', `找到 ${payments.length} 条记录,正在删除...`, 'info');
-
- for (const payment of payments) {
- await payment.destroy();
- }
-
- log('payment-log', '✅ 清空完成', 'success');
- updateStats({ totalAmount: 0, paidAmount: 0, remainingAmount: 0, finalAmount: 0 });
-
- } catch (error) {
- log('payment-log', `清空失败: ${error.message}`, 'error');
- }
- };
-
- // 4. 测试文件上传
- window.uploadFile = async function(event) {
- const file = event.target.files[0];
- if (!file) return;
-
- log('upload-log', `准备上传文件: ${file.name}`, 'info');
-
- try {
- // 初始化存储
- const storage = await NovaStorage.withCid(COMPANY_ID);
- log('upload-log', '✅ NovaStorage初始化成功', 'success');
-
- // 上传文件
- log('upload-log', '正在上传...', 'info');
- const result = await storage.upload(file, {
- prefixKey: `project/${PROJECT_ID}/test/`,
- onProgress: (progress) => {
- const percent = progress?.total?.percent || 0;
- log('upload-log', `上传进度: ${percent.toFixed(1)}%`, 'info');
- }
- });
-
- log('upload-log', `✅ 上传成功!`, 'success');
- log('upload-log', `文件名: ${result.name}`, 'info');
- log('upload-log', `大小: ${result.size} bytes`, 'info');
- log('upload-log', `URL: ${result.url}`, 'info');
-
- return result;
-
- } catch (error) {
- log('upload-log', `❌ 上传失败: ${error.message}`, 'error');
- console.error(error);
- }
- };
-
- // 5. 测试AI识别
- window.testAIRecognition = async function() {
- log('ai-log', '开始测试AI识别...', 'info');
- log('ai-log', '⚠️ 需要先上传图片才能测试AI识别', 'warning');
- log('ai-log', '请使用上方的文件上传功能', 'info');
- };
-
- // 6. 测试完整流程
- window.testFullFlow = async function() {
- log('flow-log', '========== 开始完整流程测试 ==========', 'info');
-
- try {
- // Step 1: 查询项目
- log('flow-log', 'Step 1: 查询项目信息...', 'info');
- const projectQuery = new Parse.Query('Project');
- const project = await projectQuery.get(PROJECT_ID);
- log('flow-log', `✅ 找到项目: ${project.get('title')}`, 'success');
-
- // Step 2: 查询产品
- log('flow-log', 'Step 2: 查询产品列表...', 'info');
- const productQuery = new Parse.Query('Product');
- productQuery.equalTo('project', project.toPointer());
- const products = await productQuery.find();
- log('flow-log', `✅ 找到 ${products.length} 个产品`, 'success');
-
- // Step 3: 查询付款记录
- log('flow-log', 'Step 3: 查询付款记录...', 'info');
- const paymentQuery = new Parse.Query('ProjectPayment');
- paymentQuery.equalTo('project', project.toPointer());
- const payments = await paymentQuery.find();
- log('flow-log', `✅ 找到 ${payments.length} 条付款记录`, 'success');
-
- // Step 4: 查询评价记录
- log('flow-log', 'Step 4: 查询评价记录...', 'info');
- const feedbackQuery = new Parse.Query('ProjectFeedback');
- feedbackQuery.equalTo('project', project.toPointer());
- const feedbacks = await feedbackQuery.find();
- log('flow-log', `✅ 找到 ${feedbacks.length} 条评价记录`, 'success');
-
- // Step 5: 检查归档状态
- log('flow-log', 'Step 5: 检查归档状态...', 'info');
- const data = project.get('data') || {};
- log('flow-log', `归档状态: ${data.archiveStatus ? '已归档' : '未归档'}`, 'info');
- log('flow-log', `复盘数据: ${data.retrospective ? '已生成' : '未生成'}`, 'info');
-
- log('flow-log', '========== 完整流程测试完成 ==========', 'success');
-
- } catch (error) {
- log('flow-log', `流程测试失败: ${error.message}`, 'error');
- console.error(error);
- }
- };
-
- // 页面加载时自动测试
- window.addEventListener('load', () => {
- log('payment-log', '页面加载完成,准备测试...', 'info');
- log('upload-log', 'NovaStorage文件上传准备就绪', 'info');
- log('ai-log', 'AI识别服务准备就绪', 'info');
- log('flow-log', '完整流程测试准备就绪', 'info');
- });
- </script>
- </body>
- </html>
|