Procházet zdrojové kódy

feat: 更新apikey接入文档

gatsby před 1 měsícem
rodič
revize
6cdc5716a1
1 změnil soubory, kde provedl 322 přidání a 106 odebrání
  1. 322 106
      frontend/src/views/module_payment/apikey/index.vue

+ 322 - 106
frontend/src/views/module_payment/apikey/index.vue

@@ -255,47 +255,162 @@
 
       <!-- 接入文档 -->
       <el-tab-pane label="接入文档" name="docs">
-        <div class="docs-container">
-          <el-card>
-            <template #header>
-              <div class="card-header">
-                <span>API Key认证使用说明</span>
+        <div class="docs-layout">
+          <!-- 左侧导航 -->
+          <div class="docs-sidebar">
+            <el-scrollbar>
+              <div class="sidebar-section">
+                <h3>认证</h3>
+                <ul>
+                  <li @click="activeSection = 'auth'" :class="{ active: activeSection === 'auth' }">认证方式</li>
+                  <li @click="activeSection = 'signature'" :class="{ active: activeSection === 'signature' }">签名验证</li>
+                  <li @click="activeSection = 'notes'" :class="{ active: activeSection === 'notes' }">注意事项</li>
+                </ul>
               </div>
-            </template>
-            <div class="docs-content">
-              <h2>1. 认证方式</h2>
-              <p>使用API Key进行认证时,需要在请求头中添加以下信息:</p>
-              <pre><code>Authorization: ApiKey {api_key}
+              <div class="sidebar-section">
+                <h3>账户接口</h3>
+                <ul>
+                  <li @click="activeSection = 'transfer'" :class="{ active: activeSection === 'transfer' }">转账接口</li>
+                </ul>
+              </div>
+              <div class="sidebar-section">
+                <h3>其他</h3>
+                <ul>
+                  <li @click="activeSection = 'errors'" :class="{ active: activeSection === 'errors' }">常见错误</li>
+                </ul>
+              </div>
+            </el-scrollbar>
+          </div>
+          
+          <!-- 右侧内容 -->
+          <div class="docs-content">
+            <el-card>
+              <template #header>
+                <div class="card-header">
+                  <span>{{ getSectionTitle() }}</span>
+                </div>
+              </template>
+              
+              <div v-if="activeSection === 'auth'" class="section-content">
+                <h2>1. 认证方式</h2>
+                <p>使用API Key进行认证时,需要在请求头中添加以下信息:</p>
+                <pre><code>Authorization: ApiKey {api_key}
 Signature: {signature}</code></pre>
-              <p>其中:</p>
-              <ul>
-                <li><strong>Authorization</strong>:API Key认证头,格式为 <code>ApiKey {api_key}</code></li>
-                <li><strong>Signature</strong>:请求签名(必填),用于验证请求数据的完整性</li>
-              </ul>
-
-              <h2>2. 签名验证</h2>
-              <p>签名用于验证请求数据的完整性,防止数据被篡改。签名生成步骤:</p>
-              <ol>
-                <li>将请求数据(JSON格式)按参数名升序排序</li>
-                <li>将排序后的参数拼接为字符串:<code>key1=value1&amp;key2=value2</code></li>
-                <li>使用API Secret作为密钥,通过HMAC-SHA256算法生成签名</li>
-                <li>将签名添加到请求头 <code>Signature</code> 中</li>
-              </ol>
-
-              <h2>3. 注意事项</h2>
-              <ul>
-                <li>API Key和Secret请妥善保管,不要泄露给他人</li>
-                <li>签名验证是<strong>必填</strong>的,未带签名或签名错误将返回401</li>
-                <li>签名使用HMAC-SHA256算法,密钥为API Secret</li>
-                <li>签名对象是请求体字典排序后的键值对字符串(key1=value1&amp;key2=value2)</li>
-                <li>定期更新API Key,建议每3-6个月更换一次</li>
-                <li>如发现API Key泄露,请立即禁用并重新生成</li>
-                <li>API Key有过期时间,请在过期前及时更新</li>
-              </ul>
-
-              <h2>4. cURL示例</h2>
-              <h3>4.1 租户转账接口</h3>
-              <pre><code>curl -X POST 'https://api.example.com/payment/openapi/account/transfer' \
+                <p>其中:</p>
+                <ul>
+                  <li><strong>Authorization</strong>:API Key认证头,格式为 <code>ApiKey {api_key}</code></li>
+                  <li><strong>Signature</strong>:请求签名(必填),用于验证请求数据的完整性</li>
+                </ul>
+              </div>
+              
+              <div v-else-if="activeSection === 'signature'" class="section-content">
+                <h2>2. 签名验证</h2>
+                <p>签名用于验证请求数据的完整性,防止数据被篡改。签名生成步骤:</p>
+                <ol>
+                  <li>将请求数据(JSON格式)按参数名升序排序</li>
+                  <li>将排序后的参数拼接为字符串:<code>key1=value1&amp;key2=value2</code></li>
+                  <li>使用API Secret作为密钥,通过HMAC-SHA256算法生成签名</li>
+                  <li>将签名添加到请求头 <code>Signature</code> 中</li>
+                </ol>
+                <h3>2.1 签名计算示例</h3>
+                <pre><code># 签名计算方式
+# 1. 对请求体字典按参数名升序排序
+# 2. 拼接为 key1=value1&amp;key2=value2 格式
+# 3. 使用HMAC-SHA256算法,密钥为API Secret
+# 4. 将计算结果作为Signature请求头的值</code></pre>
+              </div>
+              
+              <div v-else-if="activeSection === 'notes'" class="section-content">
+                <h2>3. 注意事项</h2>
+                <ul>
+                  <li>API Key和Secret请妥善保管,不要泄露给他人</li>
+                  <li>签名验证是<strong>必填</strong>的,未带签名或签名错误将返回401</li>
+                  <li>签名使用HMAC-SHA256算法,密钥为API Secret</li>
+                  <li>签名对象是请求体字典排序后的键值对字符串(key1=value1&amp;key2=value2)</li>
+                  <li>定期更新API Key,建议每3-6个月更换一次</li>
+                  <li>如发现API Key泄露,请立即禁用并重新生成</li>
+                  <li>API Key有过期时间,请在过期前及时更新</li>
+                </ul>
+              </div>
+              
+              <div v-else-if="activeSection === 'transfer'" class="section-content">
+                <h2>4. 转账接口</h2>
+                <h3>4.1 接口说明</h3>
+                <p>从资金账户转账到支付宝账户/银行卡</p>
+                
+                <h4>API接口地址</h4>
+                <p><code>POST https://api.qcsj88888.com/payment/openapi/account/transfer</code></p>
+                
+                <h4>请求参数</h4>
+                <table class="api-table">
+                  <thead>
+                    <tr>
+                      <th>参数名</th>
+                      <th>类型</th>
+                      <th>是否必填</th>
+                      <th>描述</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                    <tr>
+                      <td>account_book_id</td>
+                      <td>string</td>
+                      <td>是</td>
+                      <td>付款方资金账户号</td>
+                    </tr>
+                    <tr>
+                      <td>amount</td>
+                      <td>number</td>
+                      <td>是</td>
+                      <td>转账金额,单位为元,精确到小数点后两位,大于0.02元</td>
+                    </tr>
+                    <tr>
+                      <td>order_title</td>
+                      <td>string</td>
+                      <td>否</td>
+                      <td>转账标题</td>
+                    </tr>
+                    <tr>
+                      <td>remark</td>
+                      <td>string</td>
+                      <td>否</td>
+                      <td>转账备注</td>
+                    </tr>
+                    <tr>
+                      <td>payee_info</td>
+                      <td>object</td>
+                      <td>是</td>
+                      <td>收款方信息</td>
+                    </tr>
+                    <tr>
+                      <td>payee_info.identity_type</td>
+                      <td>string</td>
+                      <td>是</td>
+                      <td>收款方类型:alipay(支付宝账户)/ bank(银行卡)</td>
+                    </tr>
+                    <tr>
+                      <td>payee_info.name</td>
+                      <td>string</td>
+                      <td>是</td>
+                      <td>收款方真实姓名</td>
+                    </tr>
+                    <tr>
+                      <td>payee_info.identity</td>
+                      <td>string</td>
+                      <td>是</td>
+                      <td>收款方唯一标识(支付宝账号/银行卡号)</td>
+                    </tr>
+                    <tr>
+                      <td>payee_info.bankcard_ext_info</td>
+                      <td>object</td>
+                      <td>否</td>
+                      <td>银行卡信息(当 identity_type 为 bank 时必填)</td>
+                    </tr>
+                  </tbody>
+                </table>
+                
+                <h4>请求示例</h4>
+                <pre><code>curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/transfer' \
   -H 'Authorization: ApiKey your_api_key' \
   -H 'Signature: your_signature' \
   -H 'Content-Type: application/json' \
@@ -304,54 +419,30 @@ Signature: {signature}</code></pre>
     "amount": 100.00,
     "order_title": "转账标题",
     "payee_info": {
-      "identity_type": "ALIPAY_ACCOUNT",
+      "identity_type": "alipay",
       "name": "收款人姓名",
       "identity": "收款人支付宝账号"
     }
   }'</code></pre>
-
-              <h3>4.2 签名计算方式</h3>
-              <p>签名是对请求体对象按参数名升序排序后拼接成字符串,再进行HMAC-SHA256计算:</p>
-              <pre><code># Python签名示例
-import hashlib
-import hmac
-
-def calculate_signature(api_secret, request_data):
-    """
-    对请求体字典进行签名
-    request_data: dict 请求体数据
-    """
-    # 按参数名升序排序
-    sorted_data = sorted(request_data.items(), key=lambda x: x[0])
-    # 拼接为 key1=value1&amp;key2=value2 格式
-    sign_str = "&amp;".join([f"{k}={v}" for k, v in sorted_data])
-    # HMAC-SHA256签名
-    signature = hmac.new(
-        api_secret.encode('utf-8'),
-        sign_str.encode('utf-8'),
-        hashlib.sha256
-    ).hexdigest()
-    return signature
-
-# 示例
-api_secret = "your_api_secret"
-request_data = {
-    "account_book_id": "资金账号",
-    "amount": 100.00
-}
-signature = calculate_signature(api_secret, request_data)
-# 发送请求时设置请求头:
-# Authorization: ApiKey your_api_key
-# Signature: signature</code></pre>
-
-              <h3>4.3 常见错误</h3>
-              <ul>
-                <li><strong>401 Invalid API Key</strong>:API Key无效或已过期</li>
-                <li><strong>401 Signature header required</strong>:未提供Signature请求头</li>
-                <li><strong>401 Invalid Signature</strong>:签名验证失败,请检查签名计算方式</li>
-              </ul>
-            </div>
-          </el-card>
+                
+                <h4>响应示例</h4>
+                <pre><code>{"code": 200, "message": "转账申请已提交", "data": {"status": "DEALING", "order_no": "2026042711122334455", "fund_order_id": "2026042711122334455"}}</code></pre>
+              </div>
+              
+              
+              <div v-else-if="activeSection === 'errors'" class="section-content">
+                <h2>8. 常见错误</h2>
+                <ul>
+                  <li><strong>401 Invalid API Key</strong>:API Key无效或已过期</li>
+                  <li><strong>401 Signature header required</strong>:未提供Signature请求头</li>
+                  <li><strong>401 Invalid Signature</strong>:签名验证失败,请检查签名计算方式</li>
+                  <li><strong>400 Bad Request</strong>:请求参数错误</li>
+                  <li><strong>403 Forbidden</strong>:无权限访问</li>
+                  <li><strong>500 Internal Server Error</strong>:服务器内部错误</li>
+                </ul>
+              </div>
+            </el-card>
+          </div>
         </div>
       </el-tab-pane>
     </el-tabs>
@@ -380,11 +471,23 @@ defineOptions({
 });
 
 const activeTab = ref("management");
+const activeSection = ref("auth");
 const { searchRef, contentRef, handleQueryClick, handleResetClick, refreshList } = useCrudList();
 const dataFormRef = ref();
 const submitLoading = ref(false);
 const apiKeyDetailVisible = ref(false);
 
+function getSectionTitle() {
+  const titles = {
+    auth: "认证方式",
+    signature: "签名验证",
+    notes: "注意事项",
+    transfer: "转账接口",
+    errors: "常见错误"
+  };
+  return titles[activeSection.value] || "API文档";
+}
+
 const apiKeyDetail = reactive<ApiKeyResponse>({
   id: 0,
   api_key: "",
@@ -607,58 +710,171 @@ function downloadApiKeyCsv() {
   min-width: 0;
 }
 
-.docs-container {
+.docs-layout {
+  display: flex;
+  height: calc(100vh - 120px);
+  gap: 20px;
+}
+
+.docs-sidebar {
+  width: 280px;
+  background-color: #f5f7fa;
+  border-radius: 8px;
   padding: 20px 0;
+  overflow: hidden;
 }
 
-.card-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
+.sidebar-section {
+  margin-bottom: 24px;
+  padding: 0 20px;
+}
+
+.sidebar-section h3 {
+  font-size: 14px;
+  font-weight: bold;
+  color: #606266;
+  margin-bottom: 12px;
+  text-transform: uppercase;
+  letter-spacing: 0.5px;
+}
+
+.sidebar-section ul {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+.sidebar-section li {
+  margin-bottom: 8px;
+  padding: 8px 12px;
+  border-radius: 4px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  font-size: 14px;
+  color: #606266;
+}
+
+.sidebar-section li:hover {
+  background-color: #ecf5ff;
+  color: #409eff;
+}
+
+.sidebar-section li.active {
+  background-color: #ecf5ff;
+  color: #409eff;
+  font-weight: 500;
+  border-left: 3px solid #409eff;
 }
 
 .docs-content {
+  flex: 1;
+  overflow-y: auto;
+  padding: 0 20px;
+}
+
+.section-content {
   line-height: 1.6;
+  padding: 20px 0;
 }
 
-.docs-content h2 {
-  margin-top: 30px;
-  margin-bottom: 15px;
-  font-size: 18px;
+.section-content h2 {
+  margin-top: 0;
+  margin-bottom: 20px;
+  font-size: 20px;
   font-weight: bold;
+  color: #303133;
 }
 
-.docs-content h3 {
-  margin-top: 20px;
-  margin-bottom: 10px;
+.section-content h3 {
+  margin-top: 24px;
+  margin-bottom: 12px;
   font-size: 16px;
   font-weight: bold;
+  color: #404145;
+}
+
+.section-content h4 {
+  margin-top: 16px;
+  margin-bottom: 8px;
+  font-size: 14px;
+  font-weight: bold;
+  color: #606266;
 }
 
-.docs-content p {
-  margin-bottom: 10px;
+.section-content p {
+  margin-bottom: 12px;
+  color: #606266;
 }
 
-.docs-content ul,
-.docs-content ol {
+.section-content ul,
+.section-content ol {
   margin-left: 20px;
-  margin-bottom: 15px;
+  margin-bottom: 16px;
+  color: #606266;
 }
 
-.docs-content li {
-  margin-bottom: 5px;
+.section-content li {
+  margin-bottom: 6px;
 }
 
-.docs-content pre {
+.section-content pre {
   background-color: #f5f5f5;
-  padding: 15px;
+  padding: 16px;
   border-radius: 4px;
   overflow-x: auto;
-  margin-bottom: 15px;
+  margin-bottom: 16px;
+  border: 1px solid #e4e7ed;
 }
 
-.docs-content code {
+.section-content code {
   font-family: 'Courier New', Courier, monospace;
   font-size: 14px;
+  color: #303133;
+}
+
+.api-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-bottom: 20px;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.api-table th,
+.api-table td {
+  border: 1px solid #e4e7ed;
+  padding: 12px;
+  text-align: left;
+}
+
+.api-table th {
+  background-color: #f5f7fa;
+  font-weight: bold;
+  color: #303133;
+}
+
+.api-table tr:nth-child(even) {
+  background-color: #fafafa;
+}
+
+.api-table tr:hover {
+  background-color: #f5f7fa;
+}
+
+.card-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 20px;
+  border-bottom: 1px solid #e4e7ed;
+  margin: -20px -20px 20px -20px;
+  background-color: #fafafa;
+}
+
+.card-header span {
+  font-size: 16px;
+  font-weight: bold;
+  color: #303133;
 }
 </style>