feat(config): 添加公共目录并配置环境变量
- 在 Vite 配置中添加 publicDir 属性,指向 'public' 文件夹 - 在 Dockerfile 中设置 Vite 环境变量,用于开发和生产环境 - 更新 package.json,添加 CodeMirror 和 Milkdown 相关依赖,用于编辑器功能
This commit is contained in:
@@ -33,6 +33,7 @@ export default ({}: ConfigEnv): UserConfigExport => {
|
||||
define: {
|
||||
'process.env': {}
|
||||
},
|
||||
publicDir: 'public',
|
||||
optimizeDeps: {
|
||||
include: ['mitt', 'dayjs', 'axios', 'pinia', '@vueuse/core'],
|
||||
exclude: ['@iconify-icons/lets-icons']
|
||||
|
||||
@@ -17,6 +17,8 @@ FROM nginx:latest
|
||||
# 替换nginx中的地址
|
||||
# ARG NGINX_CONFIG_URL
|
||||
ENV NGINX_CONFIG_URL=kami_backend
|
||||
ENV VITE_ENV_SHOP_ADDR=127.0.0.1:12305
|
||||
ENV VITE_ENV_GATEWAY_ADDR=127.0.0.1:12309
|
||||
|
||||
WORKDIR /app
|
||||
# 替换默认的配置文件
|
||||
|
||||
13
package.json
13
package.json
@@ -41,8 +41,20 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@arco-design/web-vue": "^2.56.3",
|
||||
"@codemirror/commands": "^6.8.0",
|
||||
"@codemirror/lang-css": "^6.3.1",
|
||||
"@codemirror/lang-javascript": "^6.2.2",
|
||||
"@codemirror/language": "^6.10.8",
|
||||
"@codemirror/language-data": "^6.5.1",
|
||||
"@codemirror/theme-one-dark": "^6.1.2",
|
||||
"@codemirror/view": "^6.36.2",
|
||||
"@milkdown/kit": "^7.6.1",
|
||||
"@milkdown/plugin-emoji": "^7.6.1",
|
||||
"@milkdown/theme-nord": "^7.6.1",
|
||||
"@milkdown/vue": "^7.6.1",
|
||||
"@vueuse/core": "^10.11.1",
|
||||
"axios": "^1.7.9",
|
||||
"codemirror": "^6.0.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.5.1",
|
||||
@@ -66,6 +78,7 @@
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/mockjs": "^1.0.10",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
||||
|
||||
2389
pnpm-lock.yaml
generated
2389
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/assets/demo.zip
Normal file
BIN
public/assets/demo.zip
Normal file
Binary file not shown.
BIN
public/images/pay/AB4467C3-FA86-069A-99BB-C3997694311C.png
Normal file
BIN
public/images/pay/AB4467C3-FA86-069A-99BB-C3997694311C.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
431
src/assets/markdown/api.md
Normal file
431
src/assets/markdown/api.md
Normal file
@@ -0,0 +1,431 @@
|
||||
# 对接文档
|
||||
|
||||
> AppKey:**{{.payKey}}**
|
||||
> AppSecret:**{{.paySecret}}**
|
||||
|
||||
## 1.请求支付页面
|
||||
|
||||
1.DEMO文件链接[Python demo文件](/public/assets/demo.zip)
|
||||
|
||||
请求卡密支付页面,页面如下:
|
||||

|
||||
|
||||
### 请求参数
|
||||
|
||||
地址:http(s)://{{.shopHost}}/?sign=xxx
|
||||
方法:GET
|
||||
|
||||
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|
||||
| --------- | ------ | -------- | -------- | ------------------------------------------------------------------- |
|
||||
| sign | string | 是 | 签名 | 6634ddd39796e4e0a98d6f5e919ae50ddc82edbf255f15aa2e30c5c70381e7b9648 |
|
||||
| returnUrl | string | 否 | 返回地址 | 订单完成(成功或失败)后的返回地址 https://baidu.com/notify |
|
||||
|
||||
### sign生成算法
|
||||
|
||||
> 注意:生成签名时,需要提前按照参数的参数名进行排序,按照 a-z 顺序排序
|
||||
|
||||
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|
||||
| ------------- | ------ | -------- | ------------------ | ------------------------------- |
|
||||
| payKey | string | 是 | 支付 key | 20190520123456789 |
|
||||
| generatedTime | number | 是 | 支付时间 | 默认为 10 位当前时间(单位/秒) |
|
||||
| duration | number | 是 | 订单存续时间 | 默认为 24 小时 |
|
||||
| orderNo | string | 是 | 订单号(自定义生成) | 20190520123456789 |
|
||||
| notifyUrl | string | 是 | 回调地址 | https://baidu.com/notify |
|
||||
| showMMValue | string | 是 | 卡片面额 | 100 |
|
||||
| productCode | string | 是 | 卡片编码 | 苹果卡 |
|
||||
|
||||
### 通道编码
|
||||
|
||||
> 通道编码需参考后台配置,以下仅作为示例
|
||||
|
||||
| 通道 | 编码 | 说明 |
|
||||
| ---------------------------- | ---- | -------------------------------- |
|
||||
| 苹果充值卡 | 8545 | 苹果充值卡面,由卡号和卡密组成 |
|
||||
| 沃尔玛充值卡 | 8645 | 沃尔玛充值卡面,有卡号和卡密组成 |
|
||||
| 天猫店铺充值兑换\|确认收货版 | 8745 | 天猫店铺充值,用户秒收货秒回调 |
|
||||
| 天猫店铺充值兑换\|好评版 | 8645 | 天猫店铺充值,用户秒好评秒回调 |
|
||||
|
||||
### 加密算法
|
||||
|
||||
需要将上述参数加密生成 sign 参数,sign 参数需要拼接在 url
|
||||
后面,如:`http://121.37.253.228:12305/?sign=6634ddd39796e4e0a98d6f5e919ae50ddc82edbf255f15aa2e30c5c70381e7b96489f102aa574e70a4ea1b874685dfafec957b237b02d5980f0a22139d860c7d7a8d5c58e3dfbde606a0de08186a4d45228bcc1917a35768f1903bee921b78b118e8b31d25642737cb3e094c140c81f7&showMM=100&linkID=736797719398`。
|
||||
sign 加密算法为 AES/CBC 加密,数据填充模式为 PKCS7 填充,加密 key 和 iv 如下:
|
||||
|
||||
> key = thisis32bitlongpassphraseimusing
|
||||
> iv = 1234567890123456
|
||||
|
||||
##### 加密算法参考
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type OrderParams struct {
|
||||
OrderNo string `json:"orderNo"`
|
||||
PayKey string `json:"payKey"` // 支付明文秘钥
|
||||
NotifyUrl string `json:"notifyUrl"` // 回调地址
|
||||
GeneratedTime int64 `json:"generatedTime"` // 过期时间
|
||||
Duration int `json:"duration"` // 存续时间(小时)
|
||||
ProductCode string `json:"productCode"`
|
||||
ShowMMValue float64 `json:"showMMValue"`
|
||||
}
|
||||
|
||||
func String(p *OrderParams) string {
|
||||
r, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
logs.Info(string(r))
|
||||
return string(r)
|
||||
}
|
||||
|
||||
func Encrypt(p *OrderParams) string {
|
||||
prepareData := String(p)
|
||||
print(prepareData, "\n")
|
||||
if prepareData == "" {
|
||||
return prepareData
|
||||
}
|
||||
|
||||
// 加密密码数据
|
||||
key := "thisis32bitlongpassphraseimusing"
|
||||
iv := "1234567890123456"
|
||||
result, _ := AesCBCEncrypt([]byte(prepareData), []byte(key), []byte(iv))
|
||||
return hex.EncodeToString(result)
|
||||
}
|
||||
|
||||
// AesCBCEncrypt AES/CBC/PKCS7Padding 加密
|
||||
func AesCBCEncrypt(plaintext []byte, key []byte, iv []byte) ([]byte, error) {
|
||||
// AES
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// PKCS7 填充
|
||||
plaintext = paddingPKCS7(plaintext, aes.BlockSize)
|
||||
|
||||
// CBC 加密
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(plaintext, plaintext)
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// PKCS7 填充
|
||||
func paddingPKCS7(plaintext []byte, blockSize int) []byte {
|
||||
paddingSize := blockSize - len(plaintext)%blockSize
|
||||
paddingText := bytes.Repeat([]byte{byte(paddingSize)}, paddingSize)
|
||||
return append(plaintext, paddingText...)
|
||||
}
|
||||
|
||||
func main() {
|
||||
orderParams := OrderParams{
|
||||
OrderNo: "20190520123456789",
|
||||
PayKey: "20190520123456789",
|
||||
NotifyUrl: "https://baidu.com/notify",
|
||||
GeneratedTime: 1558312000,
|
||||
Duration: 24,
|
||||
ProductCode: "8645",
|
||||
ShowMMValue: 100,
|
||||
}
|
||||
sign := Encrypt(&orderParams)
|
||||
// 原始本文
|
||||
fmt.Println(sign)
|
||||
}
|
||||
|
||||
// 原始文本:{"orderNo":"20190520123456789","payKey":"20190520123456789","notifyUrl":"https://baidu.com/notify","generatedTime":1558312000,"duration":24,"productCode":"8645","showMMValue":100}
|
||||
// aes加密后的文本:94db297041a61fa78ac2176b9e8e1e9b34d2ae33b6d46fc8c731a34b4c2b76eea7738993c2c175e6d61648c31c00b5d6d465246aa39b5fba5d6b77599f112c791370486b9fb19ad675e228b1d36ec6ad890ac692a262a73f126dda2bffae493452ea20d8604874af1ff2ba67cf6aab5c5821d100beec4d4c4de86d4c014fc8fe0bfe61b259752007f498dbee92f0136b2cbb756ff5405f95fc7763405022c835812f58dda86c9d72f84c6d576d2e98909d0e499e3c4b4da552f478bfbce3ba63
|
||||
// 签名:key=thisis32bitlongpassphraseimusing iv=1234567890123456
|
||||
// 算法:CBC非对称加密/PKCS7填充
|
||||
```
|
||||
|
||||
## 2.请求实际支付金额(可选)
|
||||
|
||||
> 通过面额获取实际支付金额。注意,实际支付面额可能会随时修改,建议每次拉取订单前重新获取最新面额,切勿缓存。
|
||||
> 当前接口会返回当前面额在各个平台设置的实际支付金额,以及设置各个平台的链接,根据需要获取。
|
||||
|
||||
接口:http(s)://{{.remoteHost}}/gateway/getAllowedMM
|
||||
请求方式:GET
|
||||
|
||||
| 参数名称 | 类型 | 是否必须 | 描述 | 实例 |
|
||||
| ----------- | ------ | -------- | -------- | ----------------- |
|
||||
| showMMValue | string | 是 | 展示面额 | 充值卡上的面额 |
|
||||
| payKey | string | 是 | 支付 key | 20190520123456789 |
|
||||
| productCode | string | 卡片编码 | 是 | 8456 |
|
||||
|
||||
#### 返回参数
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| -------- | --------- | ------------ | --------------- |
|
||||
| code | int | 平台参数 | 0 成功 其他失败 |
|
||||
| msg | string | 信息提示 | 错误原因 |
|
||||
| data | interface | 具体返回数据 | 返回数据如下 |
|
||||
|
||||
具体成功返回数据
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| --------- | -------- | -------------- | ---- |
|
||||
| showLabel | string | 卡面面值 | |
|
||||
| factLabel | string | 实际面值 | |
|
||||
| linkID | string | 需要下单的链接 | |
|
||||
|
||||
## 3.提交订单(创建订单)
|
||||
|
||||
> 提交订单接口,此接口用于第三方直接提交卡号/卡密,使用自有拉单页面
|
||||
|
||||
接口:http(s)://{{.remoteHost}}/gateway/scan
|
||||
请求方式:POST
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|
||||
| ----------- | ------ | -------- | ------------------ | --------------------------------------------------- |
|
||||
| exValue | string | 是 | 扩展参数 | 卡密数据(具体格式如下) |
|
||||
| orderNo | string | 是 | 订单号 | 20190520123456789 |
|
||||
| orderPeriod | int | 否 | 订单有效期(小时) | 24 |
|
||||
| orderPrice | float | 是 | 订单价格 | 100.12 |
|
||||
| notifyUrl | string | 是 | 回调地址 | https://baidu.com/notify?sign=xxx |
|
||||
| payKey | string | 是 | 商户秘钥 | |
|
||||
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
|
||||
| sign | string | 是 | 签名 | 签名算法如下 |
|
||||
| productCode | string | 卡片编码 | 是 | 8456 |
|
||||
| ip | string | 否 | 客户端IP | 127.0.0.1 |
|
||||
| deviceId | string | 否 | 设备唯一标识 | 127.0.0.1 |
|
||||
|
||||
### 参数说明
|
||||
|
||||
#### exValue
|
||||
|
||||
内需参数
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| ------------ | -------- | -------- | ---------------------- |
|
||||
| data | string | 卡密 | --- |
|
||||
| cardNo | string | 面额 | --- |
|
||||
| recoveryType | string | 回收类型 | 2.仅有卡密 8.卡密/卡号 |
|
||||
|
||||
### 返回参数
|
||||
|
||||
返回参数
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| -------- | --------- | ------------ | --------------- |
|
||||
| code | int | 平台参数 | 0 成功 其他失败 |
|
||||
| msg | string | 信息提示 | |
|
||||
| data | interface | 具体返回数据 | 返回数据如下 |
|
||||
|
||||
具体成功返回数据
|
||||
|
||||
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|
||||
| ---------- | ------ | -------- | ------------ | ----------------- |
|
||||
| statusCode | string | 是 | 返回状态码 | 00 成功,其他失败 |
|
||||
| orderNo | string | 是 | 订单号 | 20190520123456789 |
|
||||
| orderPrice | string | 是 | 订单价格 | 100.12 |
|
||||
| sign | string | 是 | 签名 | xxx |
|
||||
| msg | string | 是 | 附带返回信息 | 成功 |
|
||||
|
||||
## 4.查询订单
|
||||
|
||||
地址:http(s)://{{.remoteHost}}/gateway/merchant/query
|
||||
方法:Get
|
||||
|
||||
查询参数
|
||||
|
||||
| 参数名称 | 参数类型 | 是否必须 | 描述 | 说明 |
|
||||
| --------- | -------- | -------- | -------- | --------------------------------------------------- |
|
||||
| orderNo | string | 是 | 订单号 | |
|
||||
| appKey | string | 是 | 应用 key | |
|
||||
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
|
||||
| sign | string | 是 | 签名 | xxx |
|
||||
|
||||
### 返回参数
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| -------- | --------- | ------------ | --------------- |
|
||||
| code | int | 平台参数 | 0 成功 其他失败 |
|
||||
| msg | string | 信息提示 | |
|
||||
| data | interface | 具体返回数据 | 返回数据如下 |
|
||||
|
||||
具体成功返回数据
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| -------- | -------- | -------- | ------------------- |
|
||||
| orderNo | string | 订单号 | |
|
||||
| cardNo | string | 卡号 | |
|
||||
| cardPwd | string | 卡密 | |
|
||||
| status | string | 订单状态 | success,fail, wait |
|
||||
| faceVal | float | 面额 | |
|
||||
| amount | string | 实际面额 | |
|
||||
|
||||
|
||||
## 4.创建订单(新)
|
||||
|
||||
> 创建订单,并返回下单单号,地址等信息
|
||||
|
||||
地址:http(s)://{{.remoteHost}}/gateway/createOrder
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 是否必须 | 描述 | 示例 |
|
||||
| ----------- | ------ | -------- | ------------------ | --------------------------------------------------- |
|
||||
| exValue | string | 是 | 扩展参数 | 卡密数据(具体格式如下) |
|
||||
| orderNo | string | 是 | 订单号 | 20190520123456789 |
|
||||
| orderPeriod | int | 否 | 订单有效期(小时) | 24 |
|
||||
| orderPrice | float | 是 | 订单价格 | 100.12 |
|
||||
| notifyUrl | string | 是 | 回调地址 | https://baidu.com/notify?sign=xxx |
|
||||
| payKey | string | 是 | 商户秘钥 | |
|
||||
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
|
||||
| sign | string | 是 | 签名 | 签名算法如下 |
|
||||
| productCode | string | 卡片编码 | 是 | 8456 |
|
||||
| timestamp | int | 是 | 时间戳 | Unix 时间戳,时区为 GMT+8 允许与服务器最大误差 30 秒 |
|
||||
|
||||
### 返回参数
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| -------- | --------- | ------------ | --------------- |
|
||||
| code | int | 平台参数 | 0 成功 -1失败 |
|
||||
| msg | string | 信息提示 | 失败的具体原因 |
|
||||
| data | interface | 具体返回数据 | 返回数据如下 |
|
||||
|
||||
具体成功返回数据
|
||||
|
||||
| 参数名称 | 参数类型 | 描述 | 说明 |
|
||||
| -------- | -------- | -------- | ------------------- |
|
||||
| productCode | string | 产品编码 | |
|
||||
| paymentName | string | 产品名称 | |
|
||||
| transactionType | string | 卡密 | 是兑换还是充值 暂时无用 |
|
||||
| payUrl | string | 支付链接 | 最终构建的支付链接
|
||||
| merchantOrderNo | string | 商户订单号 | 来源自请求传入订单号 |
|
||||
| orderNo | string | 订单编号 | 系统编号 |
|
||||
|
||||
|
||||
#### 签名算法(sign)
|
||||
|
||||
> 注意:
|
||||
> 1 对参数进行签名时,一定不要写死!!!,请按签名算法进行计算!!
|
||||
> 2 所有提交参数都需要参与签名计算 为空的也需要
|
||||
|
||||
##### 参数签名算法示例算法
|
||||
|
||||
请注意: 1.对参数进行签名时,一定不要写死!!!,请按签名算法进行计算!! 2.所有提交参数都需要参与签名计算 为空的也需要3.下面的参数只是示例,具体参数要根据实际接口参数进行验签
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//实际获取的appKey值
|
||||
appKey := "1f2811dcd32b2c5c"
|
||||
//实际获取的appSecret值
|
||||
appSecret := "3C569A210D1260B2"
|
||||
|
||||
// 如果有其它参数,依次添加 key=value
|
||||
params := map[string]string{}
|
||||
|
||||
params["appKey"] = appKey
|
||||
params["phone"] = "13800138000"
|
||||
params["timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
params["amount"] = "100"
|
||||
|
||||
strArr := SortMap(params)
|
||||
signStr := ""
|
||||
for i := 0; i < len(strArr); i++ {
|
||||
k := strArr[i]
|
||||
if len(params[k]) == 0 {
|
||||
signStr += k
|
||||
} else {
|
||||
signStr += k + params[k]
|
||||
}
|
||||
}
|
||||
signStr += appSecret
|
||||
h := md5.New()
|
||||
h.Write([]byte(signStr))
|
||||
hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// SortMap 对map的key值进行排序
|
||||
func SortMap(m map[string]string) []string {
|
||||
var arr []string
|
||||
for k := range m {
|
||||
arr = append(arr, k)
|
||||
}
|
||||
sort.Strings(arr)
|
||||
return arr
|
||||
}
|
||||
|
||||
|
||||
// 原始值
|
||||
// {
|
||||
// "amount": "100",
|
||||
// "appKey": "1f2811dcd32b2c5c",
|
||||
// "phone": "13800138000",
|
||||
// "timestamp": "1737284505"
|
||||
// }
|
||||
|
||||
// appSecret:3C569A210D1260B2
|
||||
|
||||
// 加密前的值
|
||||
// amount100appKey1f2811dcd32b2c5cphone13800138000timestamp17372845053C569A210D1260B2
|
||||
// 加密后的值:96ff597f7b89322e83e234e3ad1d42e5
|
||||
```
|
||||
|
||||
Java 算法
|
||||
|
||||
```Java
|
||||
String appSecret = "3C569A210D1260B2";
|
||||
|
||||
TreeMap<String, String> params = new TreeMap<String,String>();
|
||||
params.put("timestamp", ""+(System.currentTimeMillis()/1000L));
|
||||
params.put("phone", "13800138000");
|
||||
params.put("amount", "100");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(Entry<String, String> item : params.entrySet()){
|
||||
if(item.getKey().equals("sign"))
|
||||
continue;
|
||||
sb.append(item.getKey()).append(item.getValue());
|
||||
}
|
||||
|
||||
sb.append(appSecret);
|
||||
params.put("sign",md5(sb.toString()));
|
||||
```
|
||||
|
||||
## 订单回调接口签名检验
|
||||
|
||||
### 回调接口示例
|
||||
|
||||
地址:http://baidu.com/notify?param1=xx¶m2=xx
|
||||
方法:Get
|
||||
|
||||
返回参数:
|
||||
|
||||
| 参数名称 | 参数类型 | 含义 | 示例 |
|
||||
| ----------- | -------- | -------------------------- | ----------------- |
|
||||
| orderNo | string | 订单号(己方账号) | 20190520123456789 |
|
||||
| orderPrice | string | 订单价格(面值,一般为整数) | 100 |
|
||||
| factPrice | string | 实际价格 | 98.89 |
|
||||
| orderTime | string | 回调时间 | 2006010215:04:05 |
|
||||
| trxNo | string | 交易(系统账户)流水号 | 20190520123456789 |
|
||||
| payKey | string | 支付通道 key | 20190520123456789 |
|
||||
| sign | string | 签名 | xxx |
|
||||
| tradeStatus | string | 交易状态 | success |
|
||||
| statusCode | string | 订单状态 | success |
|
||||
|
||||
### 签名算法
|
||||
|
||||
签名算法参见`提交订单(创建订单)`接口 ↑
|
||||
179
src/assets/style/markdown.css
Normal file
179
src/assets/style/markdown.css
Normal file
@@ -0,0 +1,179 @@
|
||||
milkdown-code-block {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 24px 40px;
|
||||
background: #f5f5f5;
|
||||
margin: 20px 0;
|
||||
|
||||
.language-picker {
|
||||
width: max-content;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: none;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.language-picker.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.language-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-box .clear-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.language-button {
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: antiquewhite;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
margin-bottom: 24px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:hover .language-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.language-button:hover {
|
||||
background: bisque;
|
||||
}
|
||||
|
||||
.language-button .expand-icon {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.language-button .expand-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.language-button[data-expanded='true'] .expand-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.language-button .expand-icon svg:focus,
|
||||
.language-button .expand-icon:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
background: antiquewhite;
|
||||
border-radius: 16px;
|
||||
box-shadow:
|
||||
0px 2px 6px 0px rgba(0, 0, 0, 0.15),
|
||||
0px 1px 2px 0px rgba(0, 0, 0, 0.3);
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.language-list {
|
||||
height: 356px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.language-list-item {
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.language-list-item:hover {
|
||||
background: cornsilk;
|
||||
}
|
||||
|
||||
.language-list-item:focus-visible {
|
||||
outline: none;
|
||||
background: cornsilk;
|
||||
}
|
||||
|
||||
.language-list-item .leading,
|
||||
.language-list-item .leading svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
margin: 0 16px 12px;
|
||||
background: white;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
outline: 2px solid fuchsia;
|
||||
gap: 8px;
|
||||
padding: 0 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.search-box .search-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box .search-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.search-box .clear-icon svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.search-box input:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
/* 添加背景 */
|
||||
background: #e2e2e2;
|
||||
padding: 8px 4px;
|
||||
margin: 16px 0;
|
||||
/* 前方添加一个小柱状体 */
|
||||
position: relative;
|
||||
padding-left: 16px;
|
||||
border-left: 4px solid var(--color-primary-light-2);
|
||||
}
|
||||
|
||||
.milkdown {
|
||||
/* 设置字间距 */
|
||||
line-height: 2;
|
||||
/* 设置字间距 */
|
||||
letter-spacing: 0.05em;
|
||||
/* 设置字大小 */
|
||||
font-size: 16px;
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica,
|
||||
Arial, sans-serif;
|
||||
}
|
||||
@@ -11,6 +11,15 @@ const IFRAME: AppRouteRecordRaw = {
|
||||
requiresAuth: false
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'apiDoc',
|
||||
name: 'apiDoc',
|
||||
component: () => import('@/views/api-doc/index.vue'),
|
||||
meta: {
|
||||
locale: 'API文档',
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'merchantConfig',
|
||||
name: 'iframeMerchantConfig',
|
||||
|
||||
79
src/views/api-doc/component.vue
Normal file
79
src/views/api-doc/component.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<script setup lang="ts">
|
||||
import { Milkdown, useEditor } from '@milkdown/vue';
|
||||
import {
|
||||
defaultValueCtx,
|
||||
Editor,
|
||||
editorViewOptionsCtx,
|
||||
rootCtx
|
||||
} from '@milkdown/kit/core';
|
||||
import {
|
||||
codeBlockComponent,
|
||||
codeBlockConfig
|
||||
} from '@milkdown/kit/component/code-block';
|
||||
import { html } from '@milkdown/kit/component';
|
||||
import { nord } from '@milkdown/theme-nord';
|
||||
import doc from 'assets/markdown/api.md?raw';
|
||||
import { commonmark } from '@milkdown/kit/preset/commonmark';
|
||||
import { emoji } from '@milkdown/plugin-emoji';
|
||||
import { basicSetup } from 'codemirror';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { defaultKeymap } from '@codemirror/commands';
|
||||
import { keymap } from '@codemirror/view';
|
||||
import { languages } from '@codemirror/language-data';
|
||||
import '@milkdown/theme-nord/style.css';
|
||||
import 'assets/style/markdown.css';
|
||||
import { gfm } from '@milkdown/kit/preset/gfm';
|
||||
|
||||
let myDoc = doc
|
||||
.split('{{.remoteHost}}')
|
||||
.join(process.env.VITE_ENV_GATEWAY_ADDR);
|
||||
myDoc = doc.split('{{.shopHost}}').join(process.env.VITE_ENV_SHOP_ADDR);
|
||||
|
||||
const check = html`
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M4.5 12.75l6 6 9-13.5"
|
||||
/>
|
||||
</svg>
|
||||
`;
|
||||
useEditor(root => {
|
||||
return Editor.make()
|
||||
.config(nord)
|
||||
.config(ctx => {
|
||||
ctx.set(rootCtx, root);
|
||||
ctx.set(defaultValueCtx, myDoc);
|
||||
ctx.update(editorViewOptionsCtx, prev => ({
|
||||
...prev,
|
||||
editable: () => false
|
||||
}));
|
||||
ctx.update(codeBlockConfig.key, defaultConfig => ({
|
||||
...defaultConfig,
|
||||
languages,
|
||||
extensions: [basicSetup, oneDark, keymap.of(defaultKeymap)],
|
||||
renderLanguage: (language, selected) => {
|
||||
return html`
|
||||
<span class="leading">${selected ? check : null}</span>
|
||||
${language}
|
||||
`;
|
||||
}
|
||||
}));
|
||||
})
|
||||
.use(emoji)
|
||||
.use(gfm)
|
||||
.use(codeBlockComponent)
|
||||
.use(commonmark);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Milkdown />
|
||||
</template>
|
||||
12
src/views/api-doc/index.vue
Normal file
12
src/views/api-doc/index.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import Milkdown from './component.vue';
|
||||
import { MilkdownProvider } from '@milkdown/vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<MilkdownProvider>
|
||||
<Milkdown />
|
||||
</MilkdownProvider>
|
||||
</div>
|
||||
</template>
|
||||
@@ -29,7 +29,7 @@
|
||||
"@/*": ["src/*"],
|
||||
"@config/*": ["config/*"]
|
||||
},
|
||||
"types": ["vite/client"]
|
||||
"types": ["vite/client", "node"]
|
||||
},
|
||||
"include": ["src/**/*", "src/**/*.vue", "vite.config.ts"],
|
||||
"exclude": ["node_modules", "dist", "**/*.js"]
|
||||
|
||||
Reference in New Issue
Block a user