Commit bbaafc03 by xuzhenzhao

init

parents
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
{
"$schema": "https://unpkg.com/@changesets/config@2.1.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": true,
"fixed": [],
"linked": [
[
"@ydl-packages/*"
]
],
"access": "restricted",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
}
\ No newline at end of file
module.exports = {
types: [
{
value: 'feat', name: 'feat: A new feature'
},
{
value: 'fix', name: 'fix: A bug fix'
},
{
value: 'chore', name: 'chore: Changes to the build process'
},
{
value: 'version', name: 'version: Publish release or next version'
}
]
}
\ No newline at end of file
### VisualStudioCode template
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
### Webstorm template
.idea/
# Local History for Visual Studio Code
.history/
### Vue template
# gitignore template for Vue.js projects
#
# Recommended template: Node.gitignore
# typedoc
typedoc
### Backup template
*.bak
*.gho
*.ori
*.orig
*.tmp
### Sass template
.sass-cache/
*.css.map
*.sass.map
*.scss.map
# Dependency directories
node_modules/
# Dist
dist
\ No newline at end of file
registry=http://npm.ydl.com/
\ No newline at end of file
semi: false
singleQuote: true
printWidth: 80
trailingComma: 'none'
arrowParens: 'avoid'
\ No newline at end of file
## YDL-PACKAGES
### TODO
> toolkit
*
{
"name": "ydl-packages",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scoped": "@ydl-packages",
"scripts": {
"release": "bash scripts/publish-release.sh",
"next": "bash scripts/publish-next.sh",
"commit": "git add . && npx cz-customizable",
"preinstall": "npx only-allow pnpm",
"lib": "pnpm --filter=@ydl-packages/* run lib",
"prepublishOnly": "npm run lib"
},
"keywords": [],
"author": "xuzhenzhao",
"license": "ISC",
"dependencies": {
"prettier": "^2.7.1",
"vite": "^3.0.4"
},
"devDependencies": {
"@changesets/cli": "^2.24.1",
"cz-customizable": "^6.9.1"
}
}
# @ydl-packages/toolkit
## 1.0.2-next.1
### Patch Changes
- 3160bc6: test nex t
## 1.0.2-next.0
### Patch Changes
- 9c96c5f: next 6
## 1.0.1
### Patch Changes
- 81df464: next 2
- 47a5c55: test next
- fd91a22: test new next
- 1f40f53: test next2
- 12e060c: release
- e924d62: next 5
- 799bb63: test next
## 1.0.1-next.5
### Patch Changes
- e924d62: next 5
## 1.0.1-next.4
### Patch Changes
- 81df464: next 2
## 1.0.1-next.3
### Patch Changes
- fd91a22: test new next
## 1.0.1-next.2
### Patch Changes
- 1f40f53: test next2
## 1.0.1-next.1
### Patch Changes
- 47a5c55: test next
## 1.0.1-next.0
### Patch Changes
- 799bb63: test next
import { Utils } from '../src/Utils/Utils'
import {PayError, Payment, PayType} from '../src/Payment/Payment'
const payment = new Payment()
const MOCK_GOODS = {
totalAmount: 100,
orderId:
}
Utils.setCookie('uid', '130959612')
Utils.setCookie('accessToken', '33441f9c4be74a357b1d416d4aa616eaMjIwNw')
test('test: getBalance', async () => {
const balance = await payment.getBalance()
expect(balance).toBeGreaterThanOrEqual(0)
})
// test('test: computeAmount', () => {
// const {payAmount, payBalance} = payment.computeAmount(100)
// expect(payBalance).toBe(payment.balance)
// })
test('test: 余额支付', async () => {
const res = await payment.toPay({
totalAmount: MOCK_GOODS.totalAmount,
orderId: MOCK_GOODS.orderId,
payType: PayType.BALANCE,
quitUrl: 'https://www.baidu.com',
returnUrl: 'https://www.baidu.com',
redirectUrl: 'https://www.baidu.com'
})
if (res) {
const {errorType, success} = res
expect(errorType === PayError.VALIDATE)
}
})
// test('test: 微信支付')
// test('test: 支付宝支付')
// test('test: 微信 + 余额支付')
// test('test: 支付宝 + 余额支付')
// test('test: createBackInfoUrl')
// test('test: 订单查询')
// test('test: getPayMethodList')
// test('test: getPayChannel')
\ No newline at end of file
declare global {
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production',
YDL_ENV: "dev" | 'newDev' | 'online'
}
}
interface Window {
WeixinJSBridge: any
}
}
export { }
\ No newline at end of file
import { Payment } from 'src/Payment/Payment'
export * from 'src/Payment/Payment'
export { Payment }
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleFileExtensions: ['ts', 'tsx', 'js', 'json']
};
\ No newline at end of file
{
"name": "@ydl-packages/toolkit",
"version": "1.0.0",
"description": "",
"main": "./dist/index.umd.js",
"scripts": {
"lib": "npx vite build"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"files": [
"dist"
],
"module": "./dist/index.mjs",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.umd.js"
}
},
"dependencies": {
"@types/consola": "^2.2.5",
"axios": "^0.27.2",
"blueimp-md5": "^2.19.0",
"consola": "^2.15.3",
"js-cookie": "^3.0.1",
"mathjs": "^11.0.1",
"qs": "^6.11.0",
"regenerator-runtime": "^0.13.9",
"ts-jest": "^28.0.7",
"@types/jest": "^28.1.6"
},
"devDependencies": {
"@swc/cli": "^0.1.57",
"@swc/core": "^1.2.222",
"@types/blueimp-md5": "^2.18.0",
"@types/js-cookie": "^3.0.2",
"@types/node": "^18.6.2",
"@types/qs": "^6.9.7",
"typedoc": "^0.23.9",
"typedoc-theme-hierarchy": "^3.0.0",
"typescript": "^4.7.4",
"jest": "^28.1.3",
"jest-environment-jsdom": "^28.1.3",
"ts-node": "^10.9.1"
}
}
export const UID = 'uid'
export const ACCESS_TOKEN = 'accessToken'
\ No newline at end of file
const BASE_URL_JAVA = process.env.NODE_ENV === 'production' ? 'https://api.ydl.com' : 'https://testapi.ydl.com'
const BASE_GATEWAY = process.env.NODE_ENV === 'production' ? 'https://app2.yidianling.com' : 'https://testapp2.yidianling.com'
export const DO_UNIFIED_ORDER = `${BASE_URL_JAVA}/api/auth/cashierV2/doUnifiedOrder`
export const COMMIT_ORDER = `${BASE_URL_JAVA}/api/consult/consult/commit-order`
export const IS_PAY = `${BASE_URL_JAVA}/api/auth/Order/isPay`
export const MY_BALANCE = `${BASE_GATEWAY}/v3/uc/mybalance`
export type PayMethod = {
label: string;
value: PayType,
icon: string;
disabled: boolean
}
export const BACK_PAY_ID = 'backPayId'
export const BACK_ORDER_ID = 'backOrderId'
export type BackInfo = {
orderId: number;
payId: number
}
export type OrderStateCallBack = (params: BackInfo & { isPay: boolean }) => void
export const enum PayType {
/**
* 余额支付
*/
BALANCE = 1,
/**
* 微信支付
*/
WECHAT = 5,
/**
* 支付宝支付
*/
ALIPAY = 6,
/**
* 微信 + 余额支付
*/
WECHAT_BALANCE = 7,
/**
* 支付宝 + 余额支付
*/
ALIPAY_BALANCE = 8,
/**
* 花呗支付
*/
HUABEI = 10,
/**
* 花呗 + 余额支付
*/
HUABEI_BALANCE = 11,
/**
* 花呗分期
*/
HUABEI_STAGE = 12,
/**
* 花呗分期 + 余额支付
*/
HUABEI_STAGE_BALANCE = 13
}
export const enum PayChannel {
WX_MWEB = 'WX_MWEB',
WX_JSAPI = 'WX_JSAPI',
WX_NATIVE = 'WX_NATIVE',
WX_APP = 'WX_APP',
ALI_WAP = 'ALI_WAP',
ALI_APP = 'ALI_APP',
ALI_PC = 'ALI_PC',
ALI_QR = 'ALI_QR',
ALI_PCREDIT = 'ALI_PCREDIT'
}
export type ToPayParams = {
orderId: number;
totalAmount: number
payType: PayType;
/**
* 支付宝h5支付失败回调地址
* doc: https://opendocs.alipay.com/open/203/105285#%E9%87%8D%E8%A6%81%E5%85%A5%E5%8F%82%E8%AF%B4%E6%98%8E_3
*/
quitUrl: string;
/**
* 支付宝h5支付成功回调地址
* doc: https://opendocs.alipay.com/open/203/105285#%E9%87%8D%E8%A6%81%E5%85%A5%E5%8F%82%E8%AF%B4%E6%98%8E_3
*/
returnUrl: string;
/**
* 微信h5支付回调地址
* doc: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/combine/chapter10_1.shtml
*/
redirectUrl: string
}
export enum PayError {
WECHAT_JSSDK = "WECHAT_JSSDK",
BALANCE = 'BALANCE',
VALIDATE = 'VALIDATE',
BACKEND = 'BACKEND'
}
export type ToPayReturns = {
errorMessage?: string
errorType: PayError
success: boolean
}
export interface DoUnifiedParams extends Omit<ToPayParams, 'totalAmount' | 'redirectUrl'> {
payChannel?: PayChannel,
payBalance: number,
payAmount: number
}
export interface WechatPayParams {
appId: string,
timeStamp: string,
nonceStr: string,
signType: string,
paySign: string,
package: string
}
export const FULL_PAY_METHODS: PayMethod[] = [
{
label: '余额',
value: PayType.BALANCE,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-qb.png',
disabled: false
},
{
label: '微信支付',
value: PayType.WECHAT,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-wx.png',
disabled: false
},
{
label: '支付宝支付',
value: PayType.ALIPAY,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-zfb.png',
disabled: false
},
{
label: '微信支付',
value: PayType.WECHAT_BALANCE,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-wx.png',
disabled: false
},
{
label: '支付宝支付',
value: PayType.ALIPAY_BALANCE,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-zfb.png',
disabled: false
},
{
label: '花呗支付',
value: PayType.HUABEI,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-hb.png',
disabled: false
},
{
label: '花呗支付',
value: PayType.HUABEI_BALANCE,
icon: 'https://static.ydlcdn.com/m/order/icon-pay-hb.png',
disabled: false
}
]
\ No newline at end of file
import { DO_UNIFIED_ORDER, MY_BALANCE, IS_PAY } from "./API";
import md5 from 'blueimp-md5'
import qs from 'qs'
import { Utils } from "../Utils/Utils";
import { bignumber, subtract } from 'mathjs'
import { createRequest, defaultRequest } from "../Request/Request";
import { BackInfo, BACK_ORDER_ID, BACK_PAY_ID, DoUnifiedParams, FULL_PAY_METHODS, OrderStateCallBack, PayChannel, PayError, PayMethod, PayType, ToPayParams, ToPayReturns, WechatPayParams } from "./Defined";
import { ACCESS_TOKEN, UID } from "../Const";
export * from './Defined'
const SESSION_KEY = 'dc59cf294f37d237c1f06240568ffe21'
const createRequestForPhp = () => {
const comp = (a: string, b: string): number => {
if (a > b) {
return -1;
} else if (a == b) return 0;
else return 1;
}
const genSign = (data: Record<string, any>): string => {
let keyArr: string[] = [];
for (let i in data) {
keyArr.push(i);
}
keyArr.sort(comp);
const tempArr: string[] = [];
for (let i in keyArr) {
tempArr.push(keyArr[i] + "=" + data[keyArr[i]]);
}
return md5(tempArr.join("&") + SESSION_KEY);
}
const request = createRequest()
request.interceptors.request.use((config) => {
const requestData = {
...config.data,
ts: parseInt((Date.now() / 1000).toString()).toString(),
[UID]: Utils.getCookie(UID),
[ACCESS_TOKEN]: Utils.getCookie(ACCESS_TOKEN)
}
return {
...config,
transformRequest: [function (data: any, headers: any) {
return qs.stringify(requestData)
}],
headers: {
'content-type': 'application/x-www-form-urlencoded',
Authorization: `Ydl ${genSign(requestData)}`,
[UID]: Utils.getCookie(UID),
[ACCESS_TOKEN]: Utils.getCookie(ACCESS_TOKEN)
}
}
})
return request
}
const requestForPhp = createRequestForPhp()
const requestForJava = defaultRequest
export class Payment {
balance = 0;
constructor() {
this.getBalance()
}
public async getBalance(): Promise<number> {
try {
const { data: res } = await requestForPhp.post(MY_BALANCE, { balance: 1 })
if (res.data && res.data.balance) {
this.balance = Number(res.data.balance)
}
return this.balance
} catch (err) {
console.log(err)
return 0
}
}
public getPayMethodList(totalAmount: number): PayMethod[] {
return FULL_PAY_METHODS.filter(({ value }) => {
switch (value) {
case PayType.BALANCE:
return this.balance > 0
case PayType.WECHAT:
return this.balance === 0
case PayType.WECHAT_BALANCE:
return this.balance > 0 && this.balance < totalAmount
case PayType.ALIPAY:
return this.balance === 0 && !Utils.isWechat()
case PayType.ALIPAY_BALANCE:
return this.balance > 0 && this.balance < totalAmount && !Utils.isWechat()
case PayType.HUABEI:
return this.balance === 0 && !Utils.isWechat()
case PayType.HUABEI_BALANCE:
return this.balance > 0 && this.balance < totalAmount && !Utils.isWechat()
}
return true
}).map(item => {
const { payBalance } = this.computeAmount(totalAmount)
switch (item.value) {
case PayType.BALANCE:
return {
...item,
label: `余额支付(¥${payBalance})`,
disabled: this.balance > 0 && this.balance < totalAmount
}
}
return item
})
}
computeAmount(totalAmount: number): { payAmount: number, payBalance: number } {
let payBalance = 0, payAmount = 0
if (this.balance === 0) {
payAmount = totalAmount
} else if (this.balance > 0 && this.balance < totalAmount) {
payBalance = this.balance
payAmount = subtract(bignumber(totalAmount), bignumber(this.balance)).toNumber()
} else {
payBalance = totalAmount
}
return { payAmount, payBalance }
}
async toPay(params: ToPayParams): Promise<ToPayReturns | void> {
const { totalAmount, payType, returnUrl, orderId, redirectUrl } = params
let quitUrl = params.quitUrl
// validate
switch (payType) {
case PayType.BALANCE:
if (this.balance < totalAmount) {
return { errorMessage: '余额不足', success: false, errorType: PayError.VALIDATE }
}
}
if (!redirectUrl) {
return { errorMessage: '请填写微信回调地址页面', success: false, errorType: PayError.VALIDATE }
}
if (decodeURIComponent(redirectUrl) === redirectUrl) {
return { errorMessage: 'redirectUrl需要encode', success: false, errorType: PayError.VALIDATE }
}
// hack, 后端微信redirectUrl用的quitUrl
const payChannel = this.getPayChannel(payType)
if (payChannel === PayChannel.WX_MWEB || payChannel === PayChannel.WX_JSAPI) {
quitUrl = redirectUrl
}
const doUnifiedParams: DoUnifiedParams = {
returnUrl,
quitUrl,
orderId,
payType,
...this.computeAmount(totalAmount),
}
if (payChannel !== null) {
doUnifiedParams.payChannel = payChannel
}
const { data: res } = await requestForJava.post(DO_UNIFIED_ORDER, doUnifiedParams)
if (res.code !== '200') return { errorMessage: res.msg, success: false, errorType: PayError.BACKEND }
if (params.payType === PayType.BALANCE && res.data.balancePayResult) {
return { success: res.data.balancePayResult === 'true', errorType: PayError.BALANCE }
} else if (payChannel === PayChannel.WX_JSAPI) {
const isPaySucc = await this.wechatPayJSSDK(res.data)
return { errorMessage: isPaySucc ? '' : '微信支付失败', success: isPaySucc, errorType: PayError.WECHAT_JSSDK }
} else if (payChannel === PayChannel.WX_MWEB) {
window.location.replace(res.data.content)
} else if (payChannel === PayChannel.ALI_WAP) {
window.location.replace(res.data.content)
}
}
getPayChannel(payType: PayType): PayChannel | null {
switch (payType) {
case PayType.WECHAT_BALANCE:
case PayType.WECHAT:
return Utils.isWechat() ? PayChannel.WX_JSAPI : PayChannel.WX_MWEB
case PayType.ALIPAY:
case PayType.ALIPAY_BALANCE:
case PayType.HUABEI:
case PayType.HUABEI_BALANCE:
case PayType.HUABEI_STAGE:
case PayType.HUABEI_STAGE_BALANCE:
return PayChannel.ALI_WAP
}
return null
}
wechatPayJSSDK(wechatPayParams: WechatPayParams): Promise<boolean> {
const { appId, timeStamp, nonceStr, signType, paySign, package: packageAlias } = wechatPayParams
return new Promise((resolve) => {
window.WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
appId: appId, //公众号名称,由商户传入
timeStamp: timeStamp, //时间戳,自1970年以来的秒数
nonceStr: nonceStr, //随机串
package: packageAlias,
signType: signType, //微信签名方式:
paySign: paySign //微信签名
},
(res: any) => {
if (res.err_msg === "get_brand_wcpay_request:ok") {
resolve(true)
} else {
resolve(false)
console.error(res)
}
}
);
})
}
static async loopValidateOrderState(count = 0, callBack: OrderStateCallBack): Promise<void> {
const [, queryString] = window.location.href.split('?')
const query = queryString ? qs.parse(queryString, { ignoreQueryPrefix: true }) : {}
const returnParams: BackInfo = { payId: Number(query[BACK_PAY_ID]), orderId: Number(query[BACK_ORDER_ID]) }
const checkLoop = () => {
if (--count > 0) {
setTimeout(() => {
this.loopValidateOrderState(count, callBack)
}, 1000)
} else {
callBack({ isPay: false, ...returnParams })
}
}
if (query[BACK_PAY_ID]) {
try {
const { data: res } = await requestForJava.post(IS_PAY, {
payId: query[BACK_PAY_ID]
})
if (res.code === '200' && res.data === true) {
callBack({ isPay: true, ...returnParams })
} else {
checkLoop()
}
} catch (err) {
checkLoop()
}
}
}
/**
* 创建订单查询页面链接, 返回的url不做encode处理
* @param url
* @param backPayId
* @param backOrderId
*/
static createBackInfoUrl(url: string, backPayId: number, backOrderId: number): string {
const [path, queryString] = url.split('?')
const query = queryString ? qs.parse(queryString, { ignoreQueryPrefix: true }) : {}
query[BACK_PAY_ID] = backPayId.toString()
query[BACK_ORDER_ID] = backOrderId.toString()
return `${path}?${qs.stringify(query)}`
}
}
import axios, { Axios, AxiosRequestConfig } from 'axios'
import { ACCESS_TOKEN, UID } from '../Const'
import { Utils } from '../Utils/Utils'
export const createRequest = axios.create
const defaultRequest = axios.create()
defaultRequest.interceptors.request.use((config) => {
return {
...config,
headers: {
uid: Utils.getCookie(UID),
accessToken: Utils.getCookie(ACCESS_TOKEN)
},
}
})
export { defaultRequest }
\ No newline at end of file
import Cookies from 'js-cookie'
export class Utils {
static isWechat(): boolean {
return /MicroMessenger/i.test(window.navigator.userAgent)
}
static getCookie(key: string): string | null {
return Cookies.get(key) || null
}
static setCookie(key: 'uid' | 'accessToken', value: string): void {
Cookies.set(key, value)
}
}
\ No newline at end of file
export { Payment } from './Payment/Payment'
\ No newline at end of file
{
"entryPoints": ["src"],
"entryPointStrategy": "Expand",
"out": "typedoc",
"plugin": ["typedoc-theme-hierarchy"],
"theme": "hierarchy",
"tsconfig": "./tsconfig.json",
"name": "@ydl-packages/toolkit"
}
\ No newline at end of file
import path from 'path'
import { defineConfig } from 'vite'
export default defineConfig(() => {
return {
build: {
lib: {
entry: path.resolve(__dirname, 'src/index'),
name: 'toolkit',
fileName: 'index',
formats: ['es', 'umd'],
sourcemap: 'inline'
},
outDir: path.resolve(__dirname, 'dist')
}
}
})
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
packages:
- 'packages/*'
\ No newline at end of file
#!/bin/bash
npx changeset status
npx changeset pre enter next
npx changeset
npx changeset version --prelease
npx changeset publish
npx changeset pre exit
git add .
git commit -m "chore: pre version next"
echo -e "\n The next version was successfully generated \n"
#!/bin/bash
npx changeset status
npx changeset
npx changeset version
git add .
git commit -m "chore: pre version"
echo -e "\n The next version was successfully generated && published! \n "
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment