cloudtentacles 增加登陆后持久化, 调试ok
This commit is contained in:
@@ -84,6 +84,16 @@ module.exports = {
|
|||||||
userInfoPath: '/user/info',
|
userInfoPath: '/user/info',
|
||||||
assetPath: '/user/get_asset',
|
assetPath: '/user/get_asset',
|
||||||
permissionPath: '/user/get_permission',
|
permissionPath: '/user/get_permission',
|
||||||
|
categoriesPath: '/categories/get',
|
||||||
|
skuListPath: '/sku/list',
|
||||||
|
skuBuyPath: '/sku/buy',
|
||||||
|
knapsackPath: '/user/get_knapsack',
|
||||||
|
vnListPath: '/vn/list',
|
||||||
|
vnAppointPath: '/vn/appoint',
|
||||||
|
vnGenerateLoginCodePath: '/vn/generate_login_code',
|
||||||
|
vnVerifCodePath: '/public/vn_verif_code',
|
||||||
|
vnVerifyLoginCodePath: '/vn/verify_login_code',
|
||||||
|
vnBindUrlPath: '/vn/bind_url',
|
||||||
clientSource: 'ct-client',
|
clientSource: 'ct-client',
|
||||||
deviceId: '-',
|
deviceId: '-',
|
||||||
deviceType: 0,
|
deviceType: 0,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"token": "rEX46KZqfspDZ5CVtDcyLuo9GF5PUqsp2TOHvLuleA3zdQev8sgLJOOHiTjxxo2NLXEm6VrxNx6i9hhEdbFJQwSI",
|
||||||
|
"baseUrl": "https://123.207.217.176",
|
||||||
|
"username": "17665234375",
|
||||||
|
"phone": "17665234375",
|
||||||
|
"loggedInAt": "2026-05-02T14:56:41.055Z",
|
||||||
|
"deviceId": "-",
|
||||||
|
"deviceType": 0
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"syncFromCreatedAt": "2026-05-02T10:53:28.550Z",
|
"syncFromCreatedAt": "2026-05-02T10:53:28.550Z",
|
||||||
"lastRunStartedAt": "2026-05-02T13:46:11.938Z",
|
"lastRunStartedAt": "2026-05-02T15:00:54.051Z",
|
||||||
"lastRunFinishedAt": "2026-05-02T13:46:13.175Z",
|
"lastRunFinishedAt": "2026-05-02T15:00:55.112Z",
|
||||||
"lastRunStatus": "success",
|
"lastRunStatus": "success",
|
||||||
"lastErrorMessage": "",
|
"lastErrorMessage": "",
|
||||||
"fetchedCount": 40,
|
"fetchedCount": 40,
|
||||||
"syncedCount": 0,
|
"syncedCount": 0,
|
||||||
"ignoredCount": 40,
|
"ignoredCount": 40,
|
||||||
"lastOrderCreatedAt": "2026-05-02T13:46:02.000Z"
|
"lastOrderCreatedAt": "2026-05-02T15:00:47.000Z"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -295,6 +295,56 @@ function applyEnvOverrides(baseConfig) {
|
|||||||
nextConfig.platforms.cloudtentacles.permissionPath = cloudtentaclesPermissionPath
|
nextConfig.platforms.cloudtentacles.permissionPath = cloudtentaclesPermissionPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesCategoriesPath = String(process.env.CLOUDTENTACLES_CATEGORIES_PATH || '').trim()
|
||||||
|
if (cloudtentaclesCategoriesPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.categoriesPath = cloudtentaclesCategoriesPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesSkuListPath = String(process.env.CLOUDTENTACLES_SKU_LIST_PATH || '').trim()
|
||||||
|
if (cloudtentaclesSkuListPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.skuListPath = cloudtentaclesSkuListPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesSkuBuyPath = String(process.env.CLOUDTENTACLES_SKU_BUY_PATH || '').trim()
|
||||||
|
if (cloudtentaclesSkuBuyPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.skuBuyPath = cloudtentaclesSkuBuyPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesKnapsackPath = String(process.env.CLOUDTENTACLES_KNAPSACK_PATH || '').trim()
|
||||||
|
if (cloudtentaclesKnapsackPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.knapsackPath = cloudtentaclesKnapsackPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesVnListPath = String(process.env.CLOUDTENTACLES_VN_LIST_PATH || '').trim()
|
||||||
|
if (cloudtentaclesVnListPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.vnListPath = cloudtentaclesVnListPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesVnAppointPath = String(process.env.CLOUDTENTACLES_VN_APPOINT_PATH || '').trim()
|
||||||
|
if (cloudtentaclesVnAppointPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.vnAppointPath = cloudtentaclesVnAppointPath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesVnGenerateLoginCodePath = String(process.env.CLOUDTENTACLES_VN_GENERATE_LOGIN_CODE_PATH || '').trim()
|
||||||
|
if (cloudtentaclesVnGenerateLoginCodePath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.vnGenerateLoginCodePath = cloudtentaclesVnGenerateLoginCodePath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesVnVerifCodePath = String(process.env.CLOUDTENTACLES_VN_VERIF_CODE_PATH || '').trim()
|
||||||
|
if (cloudtentaclesVnVerifCodePath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.vnVerifCodePath = cloudtentaclesVnVerifCodePath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesVnVerifyLoginCodePath = String(process.env.CLOUDTENTACLES_VN_VERIFY_LOGIN_CODE_PATH || '').trim()
|
||||||
|
if (cloudtentaclesVnVerifyLoginCodePath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.vnVerifyLoginCodePath = cloudtentaclesVnVerifyLoginCodePath
|
||||||
|
}
|
||||||
|
|
||||||
|
const cloudtentaclesVnBindUrlPath = String(process.env.CLOUDTENTACLES_VN_BIND_URL_PATH || '').trim()
|
||||||
|
if (cloudtentaclesVnBindUrlPath) {
|
||||||
|
nextConfig.platforms.cloudtentacles.vnBindUrlPath = cloudtentaclesVnBindUrlPath
|
||||||
|
}
|
||||||
|
|
||||||
const cloudtentaclesPublicKeyPem = String(process.env.CLOUDTENTACLES_PUBLIC_KEY_PEM || '').trim()
|
const cloudtentaclesPublicKeyPem = String(process.env.CLOUDTENTACLES_PUBLIC_KEY_PEM || '').trim()
|
||||||
if (cloudtentaclesPublicKeyPem) {
|
if (cloudtentaclesPublicKeyPem) {
|
||||||
nextConfig.platforms.cloudtentacles.publicKeyPem = cloudtentaclesPublicKeyPem
|
nextConfig.platforms.cloudtentacles.publicKeyPem = cloudtentaclesPublicKeyPem
|
||||||
|
|||||||
@@ -3,10 +3,20 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from 'express'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
appointAdminCloudtentaclesVirtualNumber,
|
||||||
|
buyAdminCloudtentaclesSku,
|
||||||
|
fetchAdminCloudtentaclesVirtualNumberCode,
|
||||||
|
generateAdminCloudtentaclesLoginCode,
|
||||||
|
getAdminCloudtentaclesAsset,
|
||||||
|
getAdminCloudtentaclesBindUrl,
|
||||||
|
getAdminCloudtentaclesCategories,
|
||||||
|
getAdminCloudtentaclesKnapsack,
|
||||||
getAdminCloudtentaclesSourceConfig,
|
getAdminCloudtentaclesSourceConfig,
|
||||||
|
getAdminCloudtentaclesSkuList,
|
||||||
getAdminAgisoShopConfigs,
|
getAdminAgisoShopConfigs,
|
||||||
getAdminFulfillmentBindingConfigs,
|
getAdminFulfillmentBindingConfigs,
|
||||||
getAdminKhhaoSourceConfig,
|
getAdminKhhaoSourceConfig,
|
||||||
|
listAdminCloudtentaclesVirtualNumbers,
|
||||||
lookupAdminFulfillmentBindingOrder,
|
lookupAdminFulfillmentBindingOrder,
|
||||||
queryAdminKhhaoOrders,
|
queryAdminKhhaoOrders,
|
||||||
sendAdminCloudtentaclesSmsCode,
|
sendAdminCloudtentaclesSmsCode,
|
||||||
@@ -17,6 +27,7 @@ import {
|
|||||||
updateAdminAgisoShopConfigs,
|
updateAdminAgisoShopConfigs,
|
||||||
updateAdminKhhaoSourceConfig,
|
updateAdminKhhaoSourceConfig,
|
||||||
updateAdminFulfillmentBindingConfigs,
|
updateAdminFulfillmentBindingConfigs,
|
||||||
|
verifyAdminCloudtentaclesLoginCode,
|
||||||
validateAdminCloudtentaclesSession,
|
validateAdminCloudtentaclesSession,
|
||||||
} from '../../services/admin/admin-platform-config-service.js'
|
} from '../../services/admin/admin-platform-config-service.js'
|
||||||
import { createJsonHandler, requireAdminRoles } from './shared.js'
|
import { createJsonHandler, requireAdminRoles } from './shared.js'
|
||||||
@@ -31,6 +42,9 @@ import { createJsonHandler, requireAdminRoles } from './shared.js'
|
|||||||
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSendSmsCodeRouteBody} AdminCloudtentaclesSendSmsCodeRouteBody */
|
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSendSmsCodeRouteBody} AdminCloudtentaclesSendSmsCodeRouteBody */
|
||||||
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesTestLoginRouteBody} AdminCloudtentaclesTestLoginRouteBody */
|
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesTestLoginRouteBody} AdminCloudtentaclesTestLoginRouteBody */
|
||||||
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesValidateSessionRouteBody} AdminCloudtentaclesValidateSessionRouteBody */
|
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesValidateSessionRouteBody} AdminCloudtentaclesValidateSessionRouteBody */
|
||||||
|
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesCatalogQueryRouteBody} AdminCloudtentaclesCatalogQueryRouteBody */
|
||||||
|
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesSkuBuyRouteBody} AdminCloudtentaclesSkuBuyRouteBody */
|
||||||
|
/** @typedef {import('../../types/admin-route-inputs.js').AdminCloudtentaclesVirtualNumberRouteBody} AdminCloudtentaclesVirtualNumberRouteBody */
|
||||||
/** @typedef {import('../../types/admin-write-models.js').AdminAgisoShopConfigSaveResponse} AdminAgisoShopConfigSaveResponse */
|
/** @typedef {import('../../types/admin-write-models.js').AdminAgisoShopConfigSaveResponse} AdminAgisoShopConfigSaveResponse */
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
@@ -268,6 +282,105 @@ router.post('/platform-config/cloudtentacles/validate-session', createJsonHandle
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/asset', createJsonHandler(
|
||||||
|
(req) => getAdminCloudtentaclesAsset(/** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 余额查询成功',
|
||||||
|
errorMessage: 'cloudtentacles 余额查询失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/asset]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/categories', createJsonHandler(
|
||||||
|
(req) => getAdminCloudtentaclesCategories(/** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 分类查询成功',
|
||||||
|
errorMessage: 'cloudtentacles 分类查询失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/categories]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/sku/list', createJsonHandler(
|
||||||
|
(req) => getAdminCloudtentaclesSkuList(/** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles SKU 列表查询成功',
|
||||||
|
errorMessage: 'cloudtentacles SKU 列表查询失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/sku/list]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/sku/buy', createJsonHandler(
|
||||||
|
(req) => buyAdminCloudtentaclesSku(/** @type {AdminCloudtentaclesSkuBuyRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles SKU 购买成功',
|
||||||
|
errorMessage: 'cloudtentacles SKU 购买失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/sku/buy]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/knapsack', createJsonHandler(
|
||||||
|
(req) => getAdminCloudtentaclesKnapsack(/** @type {AdminCloudtentaclesCatalogQueryRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 背包查询成功',
|
||||||
|
errorMessage: 'cloudtentacles 背包查询失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/knapsack]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/vn/list', createJsonHandler(
|
||||||
|
(req) => listAdminCloudtentaclesVirtualNumbers(/** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 虚拟号列表查询成功',
|
||||||
|
errorMessage: 'cloudtentacles 虚拟号列表查询失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/vn/list]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/vn/appoint', createJsonHandler(
|
||||||
|
(req) => appointAdminCloudtentaclesVirtualNumber(/** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 虚拟号申请成功',
|
||||||
|
errorMessage: 'cloudtentacles 虚拟号申请失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/vn/appoint]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/vn/generate-login-code', createJsonHandler(
|
||||||
|
(req) => generateAdminCloudtentaclesLoginCode(/** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 登录码生成成功',
|
||||||
|
errorMessage: 'cloudtentacles 登录码生成失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/vn/generate-login-code]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/vn/fetch-code', createJsonHandler(
|
||||||
|
(req) => fetchAdminCloudtentaclesVirtualNumberCode(/** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 验证码获取成功',
|
||||||
|
errorMessage: 'cloudtentacles 验证码获取失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/vn/fetch-code]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/vn/verify-code', createJsonHandler(
|
||||||
|
(req) => verifyAdminCloudtentaclesLoginCode(/** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 登录码校验成功',
|
||||||
|
errorMessage: 'cloudtentacles 登录码校验失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/vn/verify-code]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
router.post('/platform-config/cloudtentacles/vn/bind-url', createJsonHandler(
|
||||||
|
(req) => getAdminCloudtentaclesBindUrl(/** @type {AdminCloudtentaclesVirtualNumberRouteBody} */ (req.body)),
|
||||||
|
{
|
||||||
|
successMessage: 'cloudtentacles 兑换链接获取成功',
|
||||||
|
errorMessage: 'cloudtentacles 兑换链接获取失败',
|
||||||
|
scope: '[admin/platform-config/cloudtentacles/vn/bind-url]',
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
router.get('/platform-config/fulfillment-bindings', createJsonHandler(
|
router.get('/platform-config/fulfillment-bindings', createJsonHandler(
|
||||||
() => getAdminFulfillmentBindingConfigs(),
|
() => getAdminFulfillmentBindingConfigs(),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,11 +20,32 @@ import {
|
|||||||
getCloudtentaclesSourcesFilePath,
|
getCloudtentaclesSourcesFilePath,
|
||||||
saveCloudtentaclesSourceConfig,
|
saveCloudtentaclesSourceConfig,
|
||||||
} from '../platforms/cloudtentacles/source-config-service.js'
|
} from '../platforms/cloudtentacles/source-config-service.js'
|
||||||
|
import {
|
||||||
|
clearCloudtentaclesSessionState,
|
||||||
|
getCloudtentaclesSessionFilePath,
|
||||||
|
getCloudtentaclesSessionState,
|
||||||
|
saveCloudtentaclesSessionState,
|
||||||
|
} from '../platforms/cloudtentacles/session-state-service.js'
|
||||||
import {
|
import {
|
||||||
loginCloudtentaclesSession,
|
loginCloudtentaclesSession,
|
||||||
sendCloudtentaclesSmsCode,
|
sendCloudtentaclesSmsCode,
|
||||||
validateCloudtentaclesSession,
|
validateCloudtentaclesSession,
|
||||||
} from '../platforms/cloudtentacles/session-service.js'
|
} from '../platforms/cloudtentacles/session-service.js'
|
||||||
|
import {
|
||||||
|
buyCloudtentaclesSku,
|
||||||
|
getCloudtentaclesAsset,
|
||||||
|
getCloudtentaclesCategories,
|
||||||
|
listCloudtentaclesSku,
|
||||||
|
} from '../platforms/cloudtentacles/catalog-service.js'
|
||||||
|
import { getCloudtentaclesKnapsack } from '../platforms/cloudtentacles/knapsack-service.js'
|
||||||
|
import {
|
||||||
|
appointCloudtentaclesVirtualNumber,
|
||||||
|
fetchCloudtentaclesVirtualNumberCode,
|
||||||
|
generateCloudtentaclesLoginCode,
|
||||||
|
getCloudtentaclesBindUrl,
|
||||||
|
listCloudtentaclesVirtualNumbers,
|
||||||
|
verifyCloudtentaclesLoginCode,
|
||||||
|
} from '../platforms/cloudtentacles/virtual-number-service.js'
|
||||||
import { normalizeAgisoMessageTemplate } from '../platforms/agiso/xianyu/message-service.js'
|
import { normalizeAgisoMessageTemplate } from '../platforms/agiso/xianyu/message-service.js'
|
||||||
import {
|
import {
|
||||||
getOrderFulfillmentBindingConfigs,
|
getOrderFulfillmentBindingConfigs,
|
||||||
@@ -46,6 +67,9 @@ import { resolveDisplayShopName } from './admin-read-shared-helpers.js'
|
|||||||
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesSendSmsCodeInput} AdminCloudtentaclesSendSmsCodeInput */
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesSendSmsCodeInput} AdminCloudtentaclesSendSmsCodeInput */
|
||||||
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesTestLoginInput} AdminCloudtentaclesTestLoginInput */
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesTestLoginInput} AdminCloudtentaclesTestLoginInput */
|
||||||
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesValidateSessionInput} AdminCloudtentaclesValidateSessionInput */
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesValidateSessionInput} AdminCloudtentaclesValidateSessionInput */
|
||||||
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesCatalogQueryInput} AdminCloudtentaclesCatalogQueryInput */
|
||||||
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesSkuBuyInput} AdminCloudtentaclesSkuBuyInput */
|
||||||
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminCloudtentaclesVirtualNumberInput} AdminCloudtentaclesVirtualNumberInput */
|
||||||
/** @typedef {import('../../types/admin-write-inputs.js').AdminFulfillmentBindingConfigSaveInput} AdminFulfillmentBindingConfigSaveInput */
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminFulfillmentBindingConfigSaveInput} AdminFulfillmentBindingConfigSaveInput */
|
||||||
/** @typedef {import('../../types/admin-write-inputs.js').AdminFulfillmentBindingLookupInput} AdminFulfillmentBindingLookupInput */
|
/** @typedef {import('../../types/admin-write-inputs.js').AdminFulfillmentBindingLookupInput} AdminFulfillmentBindingLookupInput */
|
||||||
|
|
||||||
@@ -352,9 +376,11 @@ export async function syncAdminKhhaoOrders(payload = /** @type {AdminKhhaoOrderQ
|
|||||||
|
|
||||||
export function getAdminCloudtentaclesSourceConfig() {
|
export function getAdminCloudtentaclesSourceConfig() {
|
||||||
const config = getCloudtentaclesSourceConfig()
|
const config = getCloudtentaclesSourceConfig()
|
||||||
|
const session = getCloudtentaclesSessionState()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filePath: getCloudtentaclesSourcesFilePath(),
|
filePath: getCloudtentaclesSourcesFilePath(),
|
||||||
|
sessionFilePath: getCloudtentaclesSessionFilePath(),
|
||||||
source: {
|
source: {
|
||||||
enabled: config.enabled !== false,
|
enabled: config.enabled !== false,
|
||||||
baseUrl: String(config.baseUrl || '').trim(),
|
baseUrl: String(config.baseUrl || '').trim(),
|
||||||
@@ -364,11 +390,13 @@ export function getAdminCloudtentaclesSourceConfig() {
|
|||||||
deviceId: String(config.deviceId || '-').trim() || '-',
|
deviceId: String(config.deviceId || '-').trim() || '-',
|
||||||
deviceType: Number(config.deviceType || 0),
|
deviceType: Number(config.deviceType || 0),
|
||||||
},
|
},
|
||||||
|
session: mapAdminCloudtentaclesSession(session),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
|
/** @param {AdminCloudtentaclesSourceConfigInput} [payload] */
|
||||||
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
|
export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {AdminCloudtentaclesSourceConfigInput} */ ({})) {
|
||||||
|
const current = getCloudtentaclesSourceConfig()
|
||||||
const saved = saveCloudtentaclesSourceConfig({
|
const saved = saveCloudtentaclesSourceConfig({
|
||||||
enabled: payload.enabled !== false,
|
enabled: payload.enabled !== false,
|
||||||
baseUrl: String(payload.baseUrl || '').trim() || 'https://123.207.217.176',
|
baseUrl: String(payload.baseUrl || '').trim() || 'https://123.207.217.176',
|
||||||
@@ -378,9 +406,12 @@ export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {Admin
|
|||||||
deviceId: String(payload.deviceId || '-').trim() || '-',
|
deviceId: String(payload.deviceId || '-').trim() || '-',
|
||||||
deviceType: Number(payload.deviceType || 0),
|
deviceType: Number(payload.deviceType || 0),
|
||||||
})
|
})
|
||||||
|
const shouldClearSession = hasCloudtentaclesCredentialContextChanged(current, saved)
|
||||||
|
const session = shouldClearSession ? clearCloudtentaclesSessionState() : getCloudtentaclesSessionState()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filePath: getCloudtentaclesSourcesFilePath(),
|
filePath: getCloudtentaclesSourcesFilePath(),
|
||||||
|
sessionFilePath: getCloudtentaclesSessionFilePath(),
|
||||||
source: {
|
source: {
|
||||||
enabled: saved.enabled !== false,
|
enabled: saved.enabled !== false,
|
||||||
baseUrl: String(saved.baseUrl || '').trim(),
|
baseUrl: String(saved.baseUrl || '').trim(),
|
||||||
@@ -390,6 +421,7 @@ export function updateAdminCloudtentaclesSourceConfig(payload = /** @type {Admin
|
|||||||
deviceId: String(saved.deviceId || '-').trim() || '-',
|
deviceId: String(saved.deviceId || '-').trim() || '-',
|
||||||
deviceType: Number(saved.deviceType || 0),
|
deviceType: Number(saved.deviceType || 0),
|
||||||
},
|
},
|
||||||
|
session: mapAdminCloudtentaclesSession(session),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,6 +454,15 @@ export async function testAdminCloudtentaclesLogin(payload = /** @type {AdminClo
|
|||||||
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, '-']),
|
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, '-']),
|
||||||
deviceType: payload.deviceType ?? savedSource.deviceType,
|
deviceType: payload.deviceType ?? savedSource.deviceType,
|
||||||
})
|
})
|
||||||
|
const savedSession = saveCloudtentaclesSessionState({
|
||||||
|
token: session.token,
|
||||||
|
baseUrl: session.baseUrl,
|
||||||
|
username: session.username,
|
||||||
|
phone: session.phone,
|
||||||
|
loggedInAt: session.loggedInAt,
|
||||||
|
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, '-']),
|
||||||
|
deviceType: payload.deviceType ?? savedSource.deviceType,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
baseUrl: session.baseUrl,
|
baseUrl: session.baseUrl,
|
||||||
@@ -434,6 +475,7 @@ export async function testAdminCloudtentaclesLogin(payload = /** @type {AdminClo
|
|||||||
tokenMasked: maskSecret(session.token),
|
tokenMasked: maskSecret(session.token),
|
||||||
permissionCount: session.permissions.length,
|
permissionCount: session.permissions.length,
|
||||||
permissions: session.permissions,
|
permissions: session.permissions,
|
||||||
|
persisted: Boolean(savedSession.token),
|
||||||
},
|
},
|
||||||
userInfo: session.userInfo,
|
userInfo: session.userInfo,
|
||||||
asset: session.asset,
|
asset: session.asset,
|
||||||
@@ -443,12 +485,22 @@ export async function testAdminCloudtentaclesLogin(payload = /** @type {AdminClo
|
|||||||
/** @param {AdminCloudtentaclesValidateSessionInput} [payload] */
|
/** @param {AdminCloudtentaclesValidateSessionInput} [payload] */
|
||||||
export async function validateAdminCloudtentaclesSession(payload = /** @type {AdminCloudtentaclesValidateSessionInput} */ ({})) {
|
export async function validateAdminCloudtentaclesSession(payload = /** @type {AdminCloudtentaclesValidateSessionInput} */ ({})) {
|
||||||
const savedSource = getCloudtentaclesSourceConfig()
|
const savedSource = getCloudtentaclesSourceConfig()
|
||||||
|
const persistedSession = getCloudtentaclesSessionState()
|
||||||
const session = await validateCloudtentaclesSession({
|
const session = await validateCloudtentaclesSession({
|
||||||
baseUrl: pickFirstNonEmpty([payload.baseUrl, savedSource.baseUrl, 'https://123.207.217.176']),
|
baseUrl: pickFirstNonEmpty([payload.baseUrl, savedSource.baseUrl, 'https://123.207.217.176']),
|
||||||
token: String(payload.token || '').trim(),
|
token: pickFirstNonEmpty([payload.token, persistedSession.token]),
|
||||||
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, '-']),
|
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, '-']),
|
||||||
deviceType: payload.deviceType ?? savedSource.deviceType,
|
deviceType: payload.deviceType ?? savedSource.deviceType,
|
||||||
})
|
})
|
||||||
|
const savedSession = saveCloudtentaclesSessionState({
|
||||||
|
token: session.token,
|
||||||
|
baseUrl: session.baseUrl,
|
||||||
|
username: pickFirstNonEmpty([persistedSession.username, savedSource.username]),
|
||||||
|
phone: pickFirstNonEmpty([persistedSession.phone, savedSource.phone]),
|
||||||
|
loggedInAt: session.loggedInAt,
|
||||||
|
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, persistedSession.deviceId, '-']),
|
||||||
|
deviceType: payload.deviceType ?? savedSource.deviceType ?? persistedSession.deviceType,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
baseUrl: session.baseUrl,
|
baseUrl: session.baseUrl,
|
||||||
@@ -457,12 +509,106 @@ export async function validateAdminCloudtentaclesSession(payload = /** @type {Ad
|
|||||||
tokenMasked: maskSecret(session.token),
|
tokenMasked: maskSecret(session.token),
|
||||||
permissionCount: session.permissions.length,
|
permissionCount: session.permissions.length,
|
||||||
permissions: session.permissions,
|
permissions: session.permissions,
|
||||||
|
persisted: Boolean(savedSession.token),
|
||||||
},
|
},
|
||||||
userInfo: session.userInfo,
|
userInfo: session.userInfo,
|
||||||
asset: session.asset,
|
asset: session.asset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
|
||||||
|
export async function getAdminCloudtentaclesAsset(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return getCloudtentaclesAsset(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
|
||||||
|
export async function getAdminCloudtentaclesCategories(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return getCloudtentaclesCategories(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
|
||||||
|
export async function getAdminCloudtentaclesSkuList(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return listCloudtentaclesSku(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesSkuBuyInput} [payload] */
|
||||||
|
export async function buyAdminCloudtentaclesSku(payload = /** @type {AdminCloudtentaclesSkuBuyInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return buyCloudtentaclesSku({
|
||||||
|
...context,
|
||||||
|
id: payload.id,
|
||||||
|
count: payload.count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesCatalogQueryInput} [payload] */
|
||||||
|
export async function getAdminCloudtentaclesKnapsack(payload = /** @type {AdminCloudtentaclesCatalogQueryInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return getCloudtentaclesKnapsack(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
|
||||||
|
export async function listAdminCloudtentaclesVirtualNumbers(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return listCloudtentaclesVirtualNumbers({
|
||||||
|
...context,
|
||||||
|
key: payload.key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
|
||||||
|
export async function appointAdminCloudtentaclesVirtualNumber(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return appointCloudtentaclesVirtualNumber({
|
||||||
|
...context,
|
||||||
|
key: payload.key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
|
||||||
|
export async function generateAdminCloudtentaclesLoginCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return generateCloudtentaclesLoginCode({
|
||||||
|
...context,
|
||||||
|
key: payload.key,
|
||||||
|
id: payload.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
|
||||||
|
export async function fetchAdminCloudtentaclesVirtualNumberCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return fetchCloudtentaclesVirtualNumberCode({
|
||||||
|
...context,
|
||||||
|
key: payload.key,
|
||||||
|
phone: payload.phone,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
|
||||||
|
export async function verifyAdminCloudtentaclesLoginCode(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return verifyCloudtentaclesLoginCode({
|
||||||
|
...context,
|
||||||
|
key: payload.key,
|
||||||
|
id: payload.id,
|
||||||
|
code: payload.code,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {AdminCloudtentaclesVirtualNumberInput} [payload] */
|
||||||
|
export async function getAdminCloudtentaclesBindUrl(payload = /** @type {AdminCloudtentaclesVirtualNumberInput} */ ({})) {
|
||||||
|
const context = resolveCloudtentaclesAdminContext(payload)
|
||||||
|
return getCloudtentaclesBindUrl({
|
||||||
|
...context,
|
||||||
|
key: payload.key,
|
||||||
|
id: payload.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAdminFulfillmentBindingConfigs() {
|
export async function getAdminFulfillmentBindingConfigs() {
|
||||||
const bindings = getOrderFulfillmentBindingConfigs()
|
const bindings = getOrderFulfillmentBindingConfigs()
|
||||||
const rowsResult = await query(
|
const rowsResult = await query(
|
||||||
@@ -825,6 +971,42 @@ function maskPhone(value) {
|
|||||||
return `${normalized.slice(0, 3)}****${normalized.slice(-4)}`
|
return `${normalized.slice(0, 3)}****${normalized.slice(-4)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveCloudtentaclesAdminContext(payload = {}) {
|
||||||
|
const savedSource = getCloudtentaclesSourceConfig()
|
||||||
|
const persistedSession = getCloudtentaclesSessionState()
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: pickFirstNonEmpty([payload.baseUrl, savedSource.baseUrl, 'https://123.207.217.176']),
|
||||||
|
token: pickFirstNonEmpty([payload.token, persistedSession.token]),
|
||||||
|
deviceId: pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, persistedSession.deviceId, '-']),
|
||||||
|
deviceType: payload.deviceType ?? savedSource.deviceType ?? persistedSession.deviceType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasCloudtentaclesCredentialContextChanged(current, next) {
|
||||||
|
return (
|
||||||
|
String(current.baseUrl || '').trim() !== String(next.baseUrl || '').trim()
|
||||||
|
|| String(current.username || '').trim() !== String(next.username || '').trim()
|
||||||
|
|| String(current.phone || '').trim() !== String(next.phone || '').trim()
|
||||||
|
|| String(current.deviceId || '').trim() !== String(next.deviceId || '').trim()
|
||||||
|
|| Number(current.deviceType || 0) !== Number(next.deviceType || 0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapAdminCloudtentaclesSession(session = {}) {
|
||||||
|
return {
|
||||||
|
token: String(session.token || '').trim(),
|
||||||
|
tokenMasked: maskSecret(session.token),
|
||||||
|
baseUrl: String(session.baseUrl || '').trim(),
|
||||||
|
username: String(session.username || '').trim(),
|
||||||
|
phoneMasked: maskPhone(session.phone),
|
||||||
|
loggedInAt: String(session.loggedInAt || '').trim(),
|
||||||
|
deviceId: String(session.deviceId || '-').trim() || '-',
|
||||||
|
deviceType: Number(session.deviceType || 0),
|
||||||
|
hasToken: Boolean(String(session.token || '').trim()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function isPlainObject(value) {
|
function isPlainObject(value) {
|
||||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
|
import { cloudtentaclesRequest } from './http-client.js'
|
||||||
|
import { resolveCloudtentaclesConfig } from './shared.js'
|
||||||
|
|
||||||
|
export async function getCloudtentaclesAsset(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 余额查询缺少 token', 'cloudtentacles_asset_missing_token')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.assetPath, {
|
||||||
|
...config,
|
||||||
|
method: 'GET',
|
||||||
|
token,
|
||||||
|
contentType: 'application/json',
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_asset_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
asset: Number(result.payload?.data || 0),
|
||||||
|
raw: result.payload?.data ?? null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCloudtentaclesCategories(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 分类查询缺少 token', 'cloudtentacles_categories_missing_token')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.categoriesPath, {
|
||||||
|
...config,
|
||||||
|
method: 'GET',
|
||||||
|
token,
|
||||||
|
contentType: 'application/json',
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_categories_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapCategoryItem) : []
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
itemCount: items.length,
|
||||||
|
items,
|
||||||
|
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listCloudtentaclesSku(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles SKU 列表查询缺少 token', 'cloudtentacles_sku_list_missing_token')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.skuListPath, {
|
||||||
|
...config,
|
||||||
|
method: 'GET',
|
||||||
|
token,
|
||||||
|
contentType: 'application/json',
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_sku_list_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapSkuItem) : []
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
itemCount: items.length,
|
||||||
|
items,
|
||||||
|
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function buyCloudtentaclesSku(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 购买 SKU 缺少 token', 'cloudtentacles_sku_buy_missing_token')
|
||||||
|
const skuId = requireId(payload.id, 'cloudtentacles 购买 SKU 缺少商品 id', 'cloudtentacles_sku_buy_missing_id')
|
||||||
|
const count = requireCount(payload.count)
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.skuBuyPath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: {
|
||||||
|
id: skuId,
|
||||||
|
count,
|
||||||
|
},
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_sku_buy_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
id: skuId,
|
||||||
|
count,
|
||||||
|
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapCategoryItem(item) {
|
||||||
|
const source = isPlainObject(item) ? item : {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Number(source.id || 0),
|
||||||
|
name: String(source.name || '').trim(),
|
||||||
|
supplierTag: String(source.supplier_tag || '').trim(),
|
||||||
|
description: String(source.description || '').trim(),
|
||||||
|
notes: String(source.notes || '').trim(),
|
||||||
|
expire: Number(source.expire || 0),
|
||||||
|
sendType: Number(source.send_type || 0),
|
||||||
|
exchangeUrl: String(source.exchange_url || '').trim(),
|
||||||
|
createdAt: String(source.c_time || '').trim(),
|
||||||
|
updatedAt: String(source.l_update_time || '').trim(),
|
||||||
|
raw: source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapSkuItem(item) {
|
||||||
|
const source = isPlainObject(item) ? item : {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Number(source.id || 0),
|
||||||
|
categoriesId: Number(source.categories_id || 0),
|
||||||
|
name: String(source.name || '').trim(),
|
||||||
|
description: String(source.desc || '').trim(),
|
||||||
|
image: String(source.image || '').trim(),
|
||||||
|
inventory: Number(source.inventory || 0),
|
||||||
|
price: Number(source.price || 0),
|
||||||
|
listingTime: String(source.listing_time || '').trim(),
|
||||||
|
delistingTime: String(source.delisting_time || '').trim(),
|
||||||
|
buyLimitMin: Number(source.buy_limit_min || 0),
|
||||||
|
buyLimitMax: Number(source.buy_limit_max || 0),
|
||||||
|
raw: source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireToken(value, message, errorCode) {
|
||||||
|
const token = String(value || '').trim()
|
||||||
|
if (!token) {
|
||||||
|
throw createHttpError(message, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireId(value, message, errorCode) {
|
||||||
|
const id = Number(value)
|
||||||
|
if (!Number.isInteger(id) || id <= 0) {
|
||||||
|
throw createHttpError(message, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireCount(value) {
|
||||||
|
const count = Number(value)
|
||||||
|
if (!Number.isInteger(count) || count <= 0) {
|
||||||
|
throw createHttpError('cloudtentacles 购买数量无效', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_sku_buy_invalid_count',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPlainObject(value) {
|
||||||
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
|
import { cloudtentaclesRequest } from './http-client.js'
|
||||||
|
import { resolveCloudtentaclesConfig } from './shared.js'
|
||||||
|
|
||||||
|
export async function getCloudtentaclesKnapsack(payload = {}) {
|
||||||
|
const token = String(payload.token || '').trim()
|
||||||
|
if (!token) {
|
||||||
|
throw createHttpError('cloudtentacles 背包查询缺少 token', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_knapsack_missing_token',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
const result = await cloudtentaclesRequest(config.knapsackPath, {
|
||||||
|
...config,
|
||||||
|
method: 'GET',
|
||||||
|
token,
|
||||||
|
contentType: 'application/json',
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_knapsack_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapKnapsackItem) : []
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
itemCount: items.length,
|
||||||
|
items,
|
||||||
|
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapKnapsackItem(item) {
|
||||||
|
const source = isPlainObject(item) ? item : {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Number(source.id || 0),
|
||||||
|
name: String(source.name || '').trim(),
|
||||||
|
count: Number(source.count || 0),
|
||||||
|
image: String(source.image || '').trim(),
|
||||||
|
categoriesId: Number(source.categories_id || 0),
|
||||||
|
listingTime: String(source.listing_time || '').trim(),
|
||||||
|
delistingTime: String(source.delisting_time || '').trim(),
|
||||||
|
raw: source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPlainObject(value) {
|
||||||
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import fs from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
|
||||||
|
import { PROJECT_ROOT } from '../../../config/runtime.js'
|
||||||
|
|
||||||
|
const CLOUDTENTACLES_SESSION_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-session.json')
|
||||||
|
|
||||||
|
export function getCloudtentaclesSessionFilePath() {
|
||||||
|
return CLOUDTENTACLES_SESSION_FILE_PATH
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCloudtentaclesSessionState() {
|
||||||
|
return loadCloudtentaclesSessionStateFromFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveCloudtentaclesSessionState(rawValue) {
|
||||||
|
const normalized = normalizeCloudtentaclesSessionState(rawValue)
|
||||||
|
fs.mkdirSync(path.dirname(CLOUDTENTACLES_SESSION_FILE_PATH), { recursive: true })
|
||||||
|
fs.writeFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
|
||||||
|
return normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearCloudtentaclesSessionState() {
|
||||||
|
const cleared = createDefaultCloudtentaclesSessionState()
|
||||||
|
saveCloudtentaclesSessionState(cleared)
|
||||||
|
return cleared
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadCloudtentaclesSessionStateFromFile() {
|
||||||
|
if (!fs.existsSync(CLOUDTENTACLES_SESSION_FILE_PATH)) {
|
||||||
|
return createDefaultCloudtentaclesSessionState()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rawText = fs.readFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, 'utf8')
|
||||||
|
return normalizeCloudtentaclesSessionState(JSON.parse(rawText))
|
||||||
|
} catch {
|
||||||
|
return createDefaultCloudtentaclesSessionState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCloudtentaclesSessionState(rawValue) {
|
||||||
|
const source = isPlainObject(rawValue) ? rawValue : {}
|
||||||
|
|
||||||
|
return {
|
||||||
|
token: String(source.token || '').trim(),
|
||||||
|
baseUrl: String(source.baseUrl || '').trim(),
|
||||||
|
username: String(source.username || '').trim(),
|
||||||
|
phone: String(source.phone || '').trim(),
|
||||||
|
loggedInAt: String(source.loggedInAt || '').trim(),
|
||||||
|
deviceId: String(source.deviceId || '-').trim() || '-',
|
||||||
|
deviceType: normalizeInteger(source.deviceType, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDefaultCloudtentaclesSessionState() {
|
||||||
|
return {
|
||||||
|
token: '',
|
||||||
|
baseUrl: '',
|
||||||
|
username: '',
|
||||||
|
phone: '',
|
||||||
|
loggedInAt: '',
|
||||||
|
deviceId: '-',
|
||||||
|
deviceType: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeInteger(value, fallback) {
|
||||||
|
const parsed = Number(value)
|
||||||
|
return Number.isInteger(parsed) ? parsed : fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPlainObject(value) {
|
||||||
|
return Object.prototype.toString.call(value) === '[object Object]'
|
||||||
|
}
|
||||||
@@ -14,6 +14,16 @@ export function resolveCloudtentaclesConfig(overrides = {}) {
|
|||||||
userInfoPath: '/user/info',
|
userInfoPath: '/user/info',
|
||||||
assetPath: '/user/get_asset',
|
assetPath: '/user/get_asset',
|
||||||
permissionPath: '/user/get_permission',
|
permissionPath: '/user/get_permission',
|
||||||
|
categoriesPath: '/categories/get',
|
||||||
|
skuListPath: '/sku/list',
|
||||||
|
skuBuyPath: '/sku/buy',
|
||||||
|
knapsackPath: '/user/get_knapsack',
|
||||||
|
vnListPath: '/vn/list',
|
||||||
|
vnAppointPath: '/vn/appoint',
|
||||||
|
vnGenerateLoginCodePath: '/vn/generate_login_code',
|
||||||
|
vnVerifCodePath: '/public/vn_verif_code',
|
||||||
|
vnVerifyLoginCodePath: '/vn/verify_login_code',
|
||||||
|
vnBindUrlPath: '/vn/bind_url',
|
||||||
publicKeyPem: '',
|
publicKeyPem: '',
|
||||||
clientSource: 'ct-client',
|
clientSource: 'ct-client',
|
||||||
deviceId: '-',
|
deviceId: '-',
|
||||||
@@ -28,6 +38,22 @@ export function resolveCloudtentaclesConfig(overrides = {}) {
|
|||||||
userInfoPath: normalizePath(overrides.userInfoPath || baseConfig.userInfoPath, '/user/info'),
|
userInfoPath: normalizePath(overrides.userInfoPath || baseConfig.userInfoPath, '/user/info'),
|
||||||
assetPath: normalizePath(overrides.assetPath || baseConfig.assetPath, '/user/get_asset'),
|
assetPath: normalizePath(overrides.assetPath || baseConfig.assetPath, '/user/get_asset'),
|
||||||
permissionPath: normalizePath(overrides.permissionPath || baseConfig.permissionPath, '/user/get_permission'),
|
permissionPath: normalizePath(overrides.permissionPath || baseConfig.permissionPath, '/user/get_permission'),
|
||||||
|
categoriesPath: normalizePath(overrides.categoriesPath || baseConfig.categoriesPath, '/categories/get'),
|
||||||
|
skuListPath: normalizePath(overrides.skuListPath || baseConfig.skuListPath, '/sku/list'),
|
||||||
|
skuBuyPath: normalizePath(overrides.skuBuyPath || baseConfig.skuBuyPath, '/sku/buy'),
|
||||||
|
knapsackPath: normalizePath(overrides.knapsackPath || baseConfig.knapsackPath, '/user/get_knapsack'),
|
||||||
|
vnListPath: normalizePath(overrides.vnListPath || baseConfig.vnListPath, '/vn/list'),
|
||||||
|
vnAppointPath: normalizePath(overrides.vnAppointPath || baseConfig.vnAppointPath, '/vn/appoint'),
|
||||||
|
vnGenerateLoginCodePath: normalizePath(
|
||||||
|
overrides.vnGenerateLoginCodePath || baseConfig.vnGenerateLoginCodePath,
|
||||||
|
'/vn/generate_login_code',
|
||||||
|
),
|
||||||
|
vnVerifCodePath: normalizePath(overrides.vnVerifCodePath || baseConfig.vnVerifCodePath, '/public/vn_verif_code'),
|
||||||
|
vnVerifyLoginCodePath: normalizePath(
|
||||||
|
overrides.vnVerifyLoginCodePath || baseConfig.vnVerifyLoginCodePath,
|
||||||
|
'/vn/verify_login_code',
|
||||||
|
),
|
||||||
|
vnBindUrlPath: normalizePath(overrides.vnBindUrlPath || baseConfig.vnBindUrlPath, '/vn/bind_url'),
|
||||||
publicKeyPem: normalizePem(overrides.publicKeyPem || baseConfig.publicKeyPem),
|
publicKeyPem: normalizePem(overrides.publicKeyPem || baseConfig.publicKeyPem),
|
||||||
clientSource: String(overrides.clientSource || baseConfig.clientSource || 'ct-client').trim() || 'ct-client',
|
clientSource: String(overrides.clientSource || baseConfig.clientSource || 'ct-client').trim() || 'ct-client',
|
||||||
deviceId: String(overrides.deviceId ?? baseConfig.deviceId ?? '-').trim() || '-',
|
deviceId: String(overrides.deviceId ?? baseConfig.deviceId ?? '-').trim() || '-',
|
||||||
|
|||||||
@@ -0,0 +1,222 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
|
import { cloudtentaclesRequest } from './http-client.js'
|
||||||
|
import { resolveCloudtentaclesConfig } from './shared.js'
|
||||||
|
|
||||||
|
export async function listCloudtentaclesVirtualNumbers(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 虚拟号列表缺少 token', 'cloudtentacles_vn_list_missing_token')
|
||||||
|
const key = requireKey(payload.key, 'cloudtentacles 虚拟号列表缺少 key', 'cloudtentacles_vn_list_missing_key')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.vnListPath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: { key },
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_vn_list_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapVirtualNumberItem) : []
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
key,
|
||||||
|
itemCount: items.length,
|
||||||
|
items,
|
||||||
|
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function appointCloudtentaclesVirtualNumber(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 申请虚拟号缺少 token', 'cloudtentacles_vn_appoint_missing_token')
|
||||||
|
const key = requireKey(payload.key, 'cloudtentacles 申请虚拟号缺少 key', 'cloudtentacles_vn_appoint_missing_key')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.vnAppointPath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: { key },
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_vn_appoint_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
key,
|
||||||
|
item: mapVirtualNumberItem(result.payload?.data),
|
||||||
|
rawItem: isPlainObject(result.payload?.data) ? result.payload.data : {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generateCloudtentaclesLoginCode(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 生成登录码缺少 token', 'cloudtentacles_vn_generate_code_missing_token')
|
||||||
|
const key = requireKey(payload.key, 'cloudtentacles 生成登录码缺少 key', 'cloudtentacles_vn_generate_code_missing_key')
|
||||||
|
const id = requireId(payload.id, 'cloudtentacles 生成登录码缺少 id', 'cloudtentacles_vn_generate_code_missing_id')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.vnGenerateLoginCodePath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: { key, id },
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_vn_generate_code_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
key,
|
||||||
|
id,
|
||||||
|
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchCloudtentaclesVirtualNumberCode(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 获取验证码缺少 token', 'cloudtentacles_vn_verif_code_missing_token')
|
||||||
|
const key = requireKey(payload.key, 'cloudtentacles 获取验证码缺少 key', 'cloudtentacles_vn_verif_code_missing_key')
|
||||||
|
const phone = String(payload.phone || '').trim()
|
||||||
|
if (!phone) {
|
||||||
|
throw createHttpError('cloudtentacles 获取验证码缺少手机号', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_vn_verif_code_missing_phone',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
const result = await cloudtentaclesRequest(config.vnVerifCodePath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: { key, phone },
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_vn_verif_code_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
key,
|
||||||
|
phone,
|
||||||
|
code: String(result.payload?.data || '').trim(),
|
||||||
|
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function verifyCloudtentaclesLoginCode(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 校验登录码缺少 token', 'cloudtentacles_vn_verify_code_missing_token')
|
||||||
|
const key = requireKey(payload.key, 'cloudtentacles 校验登录码缺少 key', 'cloudtentacles_vn_verify_code_missing_key')
|
||||||
|
const id = requireId(payload.id, 'cloudtentacles 校验登录码缺少 id', 'cloudtentacles_vn_verify_code_missing_id')
|
||||||
|
const code = String(payload.code || '').trim()
|
||||||
|
if (!code) {
|
||||||
|
throw createHttpError('cloudtentacles 校验登录码缺少验证码', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_vn_verify_code_missing_code',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
const result = await cloudtentaclesRequest(config.vnVerifyLoginCodePath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: { key, id, code },
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_vn_verify_code_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
key,
|
||||||
|
id,
|
||||||
|
code,
|
||||||
|
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCloudtentaclesBindUrl(payload = {}) {
|
||||||
|
const token = requireToken(payload.token, 'cloudtentacles 获取兑换链接缺少 token', 'cloudtentacles_vn_bind_url_missing_token')
|
||||||
|
const key = requireKey(payload.key, 'cloudtentacles 获取兑换链接缺少 key', 'cloudtentacles_vn_bind_url_missing_key')
|
||||||
|
const id = requireId(payload.id, 'cloudtentacles 获取兑换链接缺少 id', 'cloudtentacles_vn_bind_url_missing_id')
|
||||||
|
const config = resolveCloudtentaclesConfig(payload)
|
||||||
|
|
||||||
|
const result = await cloudtentaclesRequest(config.vnBindUrlPath, {
|
||||||
|
...config,
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
body: { id, key },
|
||||||
|
businessErrorStatusCode: 401,
|
||||||
|
businessErrorCode: 'cloudtentacles_vn_bind_url_failed',
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
baseUrl: config.baseUrl,
|
||||||
|
key,
|
||||||
|
id,
|
||||||
|
bindUrl: String(result.payload?.data || '').trim(),
|
||||||
|
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapVirtualNumberItem(item) {
|
||||||
|
const source = isPlainObject(item) ? item : {}
|
||||||
|
const bindInfoText = String(source.bind_info || '').trim()
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: Number(source.id || 0),
|
||||||
|
phone: String(source.phone || '').trim(),
|
||||||
|
status: Number(source.status || 0),
|
||||||
|
countTime: Number(source.count_time || 0),
|
||||||
|
bindInfo: tryParseJson(bindInfoText) || bindInfoText || null,
|
||||||
|
raw: source,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireToken(value, message, errorCode) {
|
||||||
|
const token = String(value || '').trim()
|
||||||
|
if (!token) {
|
||||||
|
throw createHttpError(message, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireKey(value, message, errorCode) {
|
||||||
|
const key = String(value || '').trim()
|
||||||
|
if (!key) {
|
||||||
|
throw createHttpError(message, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireId(value, message, errorCode) {
|
||||||
|
const id = Number(value)
|
||||||
|
if (!Number.isInteger(id) || id <= 0) {
|
||||||
|
throw createHttpError(message, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryParseJson(text) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(text)
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPlainObject(value) {
|
||||||
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||||
|
}
|
||||||
@@ -62,6 +62,18 @@ export {}
|
|||||||
* @typedef {import('./admin-write-inputs.js').AdminCloudtentaclesValidateSessionInput} AdminCloudtentaclesValidateSessionRouteBody
|
* @typedef {import('./admin-write-inputs.js').AdminCloudtentaclesValidateSessionInput} AdminCloudtentaclesValidateSessionRouteBody
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./admin-write-inputs.js').AdminCloudtentaclesCatalogQueryInput} AdminCloudtentaclesCatalogQueryRouteBody
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./admin-write-inputs.js').AdminCloudtentaclesSkuBuyInput} AdminCloudtentaclesSkuBuyRouteBody
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('./admin-write-inputs.js').AdminCloudtentaclesVirtualNumberInput} AdminCloudtentaclesVirtualNumberRouteBody
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('./admin-write-inputs.js').AdminFulfillmentBindingConfigSaveInput} AdminFulfillmentBindingConfigRouteBody
|
* @typedef {import('./admin-write-inputs.js').AdminFulfillmentBindingConfigSaveInput} AdminFulfillmentBindingConfigRouteBody
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -147,6 +147,39 @@ export {}
|
|||||||
* }} AdminCloudtentaclesValidateSessionInput
|
* }} AdminCloudtentaclesValidateSessionInput
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* baseUrl?: string
|
||||||
|
* token?: string
|
||||||
|
* deviceId?: string
|
||||||
|
* deviceType?: number | string
|
||||||
|
* }} AdminCloudtentaclesCatalogQueryInput
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* baseUrl?: string
|
||||||
|
* token?: string
|
||||||
|
* deviceId?: string
|
||||||
|
* deviceType?: number | string
|
||||||
|
* id?: number | string
|
||||||
|
* count?: number | string
|
||||||
|
* }} AdminCloudtentaclesSkuBuyInput
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* baseUrl?: string
|
||||||
|
* token?: string
|
||||||
|
* deviceId?: string
|
||||||
|
* deviceType?: number | string
|
||||||
|
* key?: string
|
||||||
|
* id?: number | string
|
||||||
|
* phone?: string
|
||||||
|
* code?: string
|
||||||
|
* }} AdminCloudtentaclesVirtualNumberInput
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* provider?: string
|
* provider?: string
|
||||||
|
|||||||
@@ -104,6 +104,16 @@ export {}
|
|||||||
* userInfoPath: string
|
* userInfoPath: string
|
||||||
* assetPath: string
|
* assetPath: string
|
||||||
* permissionPath: string
|
* permissionPath: string
|
||||||
|
* categoriesPath: string
|
||||||
|
* skuListPath: string
|
||||||
|
* skuBuyPath: string
|
||||||
|
* knapsackPath: string
|
||||||
|
* vnListPath: string
|
||||||
|
* vnAppointPath: string
|
||||||
|
* vnGenerateLoginCodePath: string
|
||||||
|
* vnVerifCodePath: string
|
||||||
|
* vnVerifyLoginCodePath: string
|
||||||
|
* vnBindUrlPath: string
|
||||||
* publicKeyPem: string
|
* publicKeyPem: string
|
||||||
* clientSource: string
|
* clientSource: string
|
||||||
* deviceId: string
|
* deviceId: string
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type {
|
|||||||
AdminAgisoShopConfigItem,
|
AdminAgisoShopConfigItem,
|
||||||
AdminAuditLogItem,
|
AdminAuditLogItem,
|
||||||
AdminCloudtentaclesLoginTestResult,
|
AdminCloudtentaclesLoginTestResult,
|
||||||
|
AdminCloudtentaclesPersistedSession,
|
||||||
AdminCloudtentaclesSendSmsResult,
|
AdminCloudtentaclesSendSmsResult,
|
||||||
AdminCloudtentaclesSourceConfig,
|
AdminCloudtentaclesSourceConfig,
|
||||||
AdminCloudtentaclesValidateSessionResult,
|
AdminCloudtentaclesValidateSessionResult,
|
||||||
@@ -152,14 +153,18 @@ export function syncAdminKhhaoOrders(payload: {
|
|||||||
export function fetchAdminCloudtentaclesSourceConfig() {
|
export function fetchAdminCloudtentaclesSourceConfig() {
|
||||||
return apiGet<{
|
return apiGet<{
|
||||||
filePath: string
|
filePath: string
|
||||||
|
sessionFilePath: string
|
||||||
source: AdminCloudtentaclesSourceConfig
|
source: AdminCloudtentaclesSourceConfig
|
||||||
|
session: AdminCloudtentaclesPersistedSession
|
||||||
}>('/api/v1/admin/platform-config/cloudtentacles-source')
|
}>('/api/v1/admin/platform-config/cloudtentacles-source')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveAdminCloudtentaclesSourceConfig(payload: AdminCloudtentaclesSourceConfig) {
|
export function saveAdminCloudtentaclesSourceConfig(payload: AdminCloudtentaclesSourceConfig) {
|
||||||
return apiPost<{
|
return apiPost<{
|
||||||
filePath: string
|
filePath: string
|
||||||
|
sessionFilePath: string
|
||||||
source: AdminCloudtentaclesSourceConfig
|
source: AdminCloudtentaclesSourceConfig
|
||||||
|
session: AdminCloudtentaclesPersistedSession
|
||||||
}>('/api/v1/admin/platform-config/cloudtentacles-source', payload as unknown as Record<string, unknown>)
|
}>('/api/v1/admin/platform-config/cloudtentacles-source', payload as unknown as Record<string, unknown>)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +199,118 @@ export function validateAdminCloudtentaclesSession(payload: {
|
|||||||
return apiPost<AdminCloudtentaclesValidateSessionResult>('/api/v1/admin/platform-config/cloudtentacles/validate-session', payload)
|
return apiPost<AdminCloudtentaclesValidateSessionResult>('/api/v1/admin/platform-config/cloudtentacles/validate-session', payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesAsset(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/asset', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesCategories(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/categories', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesSkuList(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/sku/list', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buyAdminCloudtentaclesSku(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
id?: number
|
||||||
|
count?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/sku/buy', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesKnapsack(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/knapsack', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesVnList(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
key?: string
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/vn/list', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function appointAdminCloudtentaclesVn(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
key?: string
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/vn/appoint', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateAdminCloudtentaclesVnLoginCode(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
key?: string
|
||||||
|
id?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/vn/generate-login-code', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesVnCode(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
key?: string
|
||||||
|
phone?: string
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/vn/fetch-code', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyAdminCloudtentaclesVnCode(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
key?: string
|
||||||
|
id?: number
|
||||||
|
code?: string
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/vn/verify-code', payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchAdminCloudtentaclesBindUrl(payload: {
|
||||||
|
baseUrl?: string
|
||||||
|
token?: string
|
||||||
|
deviceId?: string
|
||||||
|
deviceType?: number
|
||||||
|
key?: string
|
||||||
|
id?: number
|
||||||
|
}) {
|
||||||
|
return apiPost<Record<string, unknown>>('/api/v1/admin/platform-config/cloudtentacles/vn/bind-url', payload)
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchAdminFulfillmentBindingConfigs() {
|
export function fetchAdminFulfillmentBindingConfigs() {
|
||||||
return apiGet<{
|
return apiGet<{
|
||||||
filePath: string
|
filePath: string
|
||||||
|
|||||||
@@ -185,6 +185,18 @@ export interface AdminCloudtentaclesSourceConfig {
|
|||||||
deviceType: number
|
deviceType: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AdminCloudtentaclesPersistedSession {
|
||||||
|
token: string
|
||||||
|
tokenMasked: string
|
||||||
|
baseUrl: string
|
||||||
|
username: string
|
||||||
|
phoneMasked: string
|
||||||
|
loggedInAt: string
|
||||||
|
deviceId: string
|
||||||
|
deviceType: number
|
||||||
|
hasToken: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface AdminCloudtentaclesSendSmsResult {
|
export interface AdminCloudtentaclesSendSmsResult {
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
username: string
|
username: string
|
||||||
@@ -198,6 +210,7 @@ export interface AdminCloudtentaclesSessionSummary {
|
|||||||
tokenMasked: string
|
tokenMasked: string
|
||||||
permissionCount: number
|
permissionCount: number
|
||||||
permissions: string[]
|
permissions: string[]
|
||||||
|
persisted?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminCloudtentaclesLoginTestResult {
|
export interface AdminCloudtentaclesLoginTestResult {
|
||||||
|
|||||||
@@ -3,9 +3,19 @@ import { computed, onMounted, ref } from 'vue'
|
|||||||
|
|
||||||
import { showError, showSuccess } from '@/lib/feedback'
|
import { showError, showSuccess } from '@/lib/feedback'
|
||||||
import {
|
import {
|
||||||
|
appointAdminCloudtentaclesVn,
|
||||||
|
buyAdminCloudtentaclesSku,
|
||||||
|
fetchAdminCloudtentaclesAsset,
|
||||||
|
fetchAdminCloudtentaclesBindUrl,
|
||||||
|
fetchAdminCloudtentaclesCategories,
|
||||||
|
fetchAdminCloudtentaclesKnapsack,
|
||||||
fetchAdminAgisoShopConfigs,
|
fetchAdminAgisoShopConfigs,
|
||||||
fetchAdminCloudtentaclesSourceConfig,
|
fetchAdminCloudtentaclesSourceConfig,
|
||||||
|
fetchAdminCloudtentaclesSkuList,
|
||||||
|
fetchAdminCloudtentaclesVnCode,
|
||||||
|
fetchAdminCloudtentaclesVnList,
|
||||||
fetchAdminKhhaoSourceConfig,
|
fetchAdminKhhaoSourceConfig,
|
||||||
|
generateAdminCloudtentaclesVnLoginCode,
|
||||||
queryAdminKhhaoOrders,
|
queryAdminKhhaoOrders,
|
||||||
saveAdminCloudtentaclesSourceConfig,
|
saveAdminCloudtentaclesSourceConfig,
|
||||||
saveAdminAgisoShopConfigs,
|
saveAdminAgisoShopConfigs,
|
||||||
@@ -15,12 +25,14 @@ import {
|
|||||||
testAdminCloudtentaclesLogin,
|
testAdminCloudtentaclesLogin,
|
||||||
testAdminKhhaoLogin,
|
testAdminKhhaoLogin,
|
||||||
validateAdminCloudtentaclesSession,
|
validateAdminCloudtentaclesSession,
|
||||||
|
verifyAdminCloudtentaclesVnCode,
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type {
|
||||||
AdminAgisoMessagingDefaults,
|
AdminAgisoMessagingDefaults,
|
||||||
AdminAgisoObservedShopItem,
|
AdminAgisoObservedShopItem,
|
||||||
AdminAgisoShopConfigItem,
|
AdminAgisoShopConfigItem,
|
||||||
AdminCloudtentaclesLoginTestResult,
|
AdminCloudtentaclesLoginTestResult,
|
||||||
|
AdminCloudtentaclesPersistedSession,
|
||||||
AdminCloudtentaclesSendSmsResult,
|
AdminCloudtentaclesSendSmsResult,
|
||||||
AdminCloudtentaclesSourceConfig,
|
AdminCloudtentaclesSourceConfig,
|
||||||
AdminCloudtentaclesValidateSessionResult,
|
AdminCloudtentaclesValidateSessionResult,
|
||||||
@@ -50,6 +62,7 @@ type EditableShop = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
const isDevMode = import.meta.env.DEV
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const khhaoSaving = ref(false)
|
const khhaoSaving = ref(false)
|
||||||
const cloudtentaclesSaving = ref(false)
|
const cloudtentaclesSaving = ref(false)
|
||||||
@@ -60,6 +73,7 @@ const agisoFilePath = ref('')
|
|||||||
const khhaoFilePath = ref('')
|
const khhaoFilePath = ref('')
|
||||||
const khhaoStateFilePath = ref('')
|
const khhaoStateFilePath = ref('')
|
||||||
const cloudtentaclesFilePath = ref('')
|
const cloudtentaclesFilePath = ref('')
|
||||||
|
const cloudtentaclesSessionFilePath = ref('')
|
||||||
const defaults = ref<EditableDefaults>(createEmptyDefaults())
|
const defaults = ref<EditableDefaults>(createEmptyDefaults())
|
||||||
const shops = ref<EditableShop[]>([])
|
const shops = ref<EditableShop[]>([])
|
||||||
const observedShops = ref<AdminAgisoObservedShopItem[]>([])
|
const observedShops = ref<AdminAgisoObservedShopItem[]>([])
|
||||||
@@ -92,6 +106,10 @@ const cloudtentaclesForm = ref({
|
|||||||
phone: '',
|
phone: '',
|
||||||
code: '',
|
code: '',
|
||||||
token: '',
|
token: '',
|
||||||
|
vnKey: '1',
|
||||||
|
vnId: 0,
|
||||||
|
skuId: 0,
|
||||||
|
skuCount: 1,
|
||||||
deviceId: '-',
|
deviceId: '-',
|
||||||
deviceType: 0,
|
deviceType: 0,
|
||||||
})
|
})
|
||||||
@@ -102,6 +120,9 @@ const cloudtentaclesResultError = ref('')
|
|||||||
const cloudtentaclesSmsResult = ref<AdminCloudtentaclesSendSmsResult | null>(null)
|
const cloudtentaclesSmsResult = ref<AdminCloudtentaclesSendSmsResult | null>(null)
|
||||||
const cloudtentaclesLoginResult = ref<AdminCloudtentaclesLoginTestResult | null>(null)
|
const cloudtentaclesLoginResult = ref<AdminCloudtentaclesLoginTestResult | null>(null)
|
||||||
const cloudtentaclesValidateResult = ref<AdminCloudtentaclesValidateSessionResult | null>(null)
|
const cloudtentaclesValidateResult = ref<AdminCloudtentaclesValidateSessionResult | null>(null)
|
||||||
|
const cloudtentaclesDebugLoading = ref(false)
|
||||||
|
const cloudtentaclesDebugResult = ref('')
|
||||||
|
const cloudtentaclesPersistedSession = ref<AdminCloudtentaclesPersistedSession | null>(null)
|
||||||
|
|
||||||
const agisoStats = computed(() => ({
|
const agisoStats = computed(() => ({
|
||||||
configuredShopCount: shops.value.length,
|
configuredShopCount: shops.value.length,
|
||||||
@@ -203,13 +224,19 @@ async function loadConfigs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cloudtentaclesFilePath.value = cloudtentaclesResponse.data.filePath
|
cloudtentaclesFilePath.value = cloudtentaclesResponse.data.filePath
|
||||||
|
cloudtentaclesSessionFilePath.value = cloudtentaclesResponse.data.sessionFilePath
|
||||||
|
cloudtentaclesPersistedSession.value = cloudtentaclesResponse.data.session
|
||||||
cloudtentaclesForm.value = {
|
cloudtentaclesForm.value = {
|
||||||
baseUrl: cloudtentaclesResponse.data.source.baseUrl || 'https://123.207.217.176',
|
baseUrl: cloudtentaclesResponse.data.source.baseUrl || 'https://123.207.217.176',
|
||||||
username: cloudtentaclesResponse.data.source.username || '',
|
username: cloudtentaclesResponse.data.source.username || '',
|
||||||
password: cloudtentaclesResponse.data.source.password || '',
|
password: cloudtentaclesResponse.data.source.password || '',
|
||||||
phone: cloudtentaclesResponse.data.source.phone || '',
|
phone: cloudtentaclesResponse.data.source.phone || '',
|
||||||
code: '',
|
code: '',
|
||||||
token: '',
|
token: cloudtentaclesResponse.data.session?.token || '',
|
||||||
|
vnKey: '1',
|
||||||
|
vnId: 0,
|
||||||
|
skuId: 0,
|
||||||
|
skuCount: 1,
|
||||||
deviceId: cloudtentaclesResponse.data.source.deviceId || '-',
|
deviceId: cloudtentaclesResponse.data.source.deviceId || '-',
|
||||||
deviceType: cloudtentaclesResponse.data.source.deviceType || 0,
|
deviceType: cloudtentaclesResponse.data.source.deviceType || 0,
|
||||||
}
|
}
|
||||||
@@ -492,6 +519,9 @@ async function handleCloudtentaclesSaveSource() {
|
|||||||
try {
|
try {
|
||||||
const response = await saveAdminCloudtentaclesSourceConfig(buildCloudtentaclesConfigPayload())
|
const response = await saveAdminCloudtentaclesSourceConfig(buildCloudtentaclesConfigPayload())
|
||||||
cloudtentaclesFilePath.value = response.data.filePath
|
cloudtentaclesFilePath.value = response.data.filePath
|
||||||
|
cloudtentaclesSessionFilePath.value = response.data.sessionFilePath
|
||||||
|
cloudtentaclesPersistedSession.value = response.data.session
|
||||||
|
cloudtentaclesForm.value.token = response.data.session?.token || ''
|
||||||
showSuccess('cloudtentacles 履约平台配置已保存')
|
showSuccess('cloudtentacles 履约平台配置已保存')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
cloudtentaclesResultError.value = error instanceof Error ? error.message : 'cloudtentacles 配置保存失败'
|
cloudtentaclesResultError.value = error instanceof Error ? error.message : 'cloudtentacles 配置保存失败'
|
||||||
@@ -533,6 +563,17 @@ async function handleCloudtentaclesTestLogin() {
|
|||||||
const response = await testAdminCloudtentaclesLogin(buildCloudtentaclesLoginPayload())
|
const response = await testAdminCloudtentaclesLogin(buildCloudtentaclesLoginPayload())
|
||||||
cloudtentaclesLoginResult.value = response.data
|
cloudtentaclesLoginResult.value = response.data
|
||||||
cloudtentaclesForm.value.token = response.data.token || cloudtentaclesForm.value.token
|
cloudtentaclesForm.value.token = response.data.token || cloudtentaclesForm.value.token
|
||||||
|
cloudtentaclesPersistedSession.value = {
|
||||||
|
token: response.data.token || '',
|
||||||
|
tokenMasked: response.data.session.tokenMasked,
|
||||||
|
baseUrl: response.data.baseUrl,
|
||||||
|
username: response.data.username,
|
||||||
|
phoneMasked: response.data.phoneMasked,
|
||||||
|
loggedInAt: response.data.loggedInAt,
|
||||||
|
deviceId: cloudtentaclesForm.value.deviceId.trim() || '-',
|
||||||
|
deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
|
||||||
|
hasToken: Boolean(response.data.token),
|
||||||
|
}
|
||||||
showSuccess('cloudtentacles 登录测试成功')
|
showSuccess('cloudtentacles 登录测试成功')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
cloudtentaclesResultError.value = error instanceof Error ? error.message : 'cloudtentacles 登录测试失败'
|
cloudtentaclesResultError.value = error instanceof Error ? error.message : 'cloudtentacles 登录测试失败'
|
||||||
@@ -560,6 +601,17 @@ async function handleCloudtentaclesValidateSession() {
|
|||||||
deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
|
deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
|
||||||
})
|
})
|
||||||
cloudtentaclesValidateResult.value = response.data
|
cloudtentaclesValidateResult.value = response.data
|
||||||
|
cloudtentaclesPersistedSession.value = {
|
||||||
|
token,
|
||||||
|
tokenMasked: response.data.session.tokenMasked,
|
||||||
|
baseUrl: response.data.baseUrl,
|
||||||
|
username: cloudtentaclesPersistedSession.value?.username || cloudtentaclesForm.value.username.trim(),
|
||||||
|
phoneMasked: cloudtentaclesPersistedSession.value?.phoneMasked || '',
|
||||||
|
loggedInAt: response.data.loggedInAt,
|
||||||
|
deviceId: cloudtentaclesForm.value.deviceId.trim() || '-',
|
||||||
|
deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
|
||||||
|
hasToken: Boolean(token),
|
||||||
|
}
|
||||||
showSuccess('cloudtentacles 会话校验成功')
|
showSuccess('cloudtentacles 会话校验成功')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
cloudtentaclesResultError.value = error instanceof Error ? error.message : 'cloudtentacles 会话校验失败'
|
cloudtentaclesResultError.value = error instanceof Error ? error.message : 'cloudtentacles 会话校验失败'
|
||||||
@@ -569,6 +621,142 @@ async function handleCloudtentaclesValidateSession() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildCloudtentaclesTokenPayload() {
|
||||||
|
return {
|
||||||
|
baseUrl: cloudtentaclesForm.value.baseUrl.trim() || 'https://123.207.217.176',
|
||||||
|
token: cloudtentaclesForm.value.token.trim(),
|
||||||
|
deviceId: cloudtentaclesForm.value.deviceId.trim() || '-',
|
||||||
|
deviceType: Number(cloudtentaclesForm.value.deviceType || 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureCloudtentaclesToken() {
|
||||||
|
if (!cloudtentaclesForm.value.token.trim()) {
|
||||||
|
cloudtentaclesResultError.value = '请先登录或手动填写 token'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCloudtentaclesDebugResult(label: string, data: unknown) {
|
||||||
|
cloudtentaclesDebugResult.value = `${label}\n${JSON.stringify(data, null, 2)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runCloudtentaclesDebugAction(label: string, runner: () => Promise<{ data: unknown }>) {
|
||||||
|
cloudtentaclesDebugLoading.value = true
|
||||||
|
cloudtentaclesResultError.value = ''
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await runner()
|
||||||
|
renderCloudtentaclesDebugResult(label, response.data)
|
||||||
|
showSuccess(`${label}成功`)
|
||||||
|
} catch (error) {
|
||||||
|
cloudtentaclesResultError.value = error instanceof Error ? error.message : `${label}失败`
|
||||||
|
showError(cloudtentaclesResultError.value)
|
||||||
|
} finally {
|
||||||
|
cloudtentaclesDebugLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchAsset() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('查询余额', () => fetchAdminCloudtentaclesAsset(buildCloudtentaclesTokenPayload()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchCategories() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('查询分类', () => fetchAdminCloudtentaclesCategories(buildCloudtentaclesTokenPayload()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchSkuList() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('查询SKU列表', () => fetchAdminCloudtentaclesSkuList(buildCloudtentaclesTokenPayload()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesBuySku() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('购买SKU', () => buyAdminCloudtentaclesSku({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
id: Number(cloudtentaclesForm.value.skuId || 0),
|
||||||
|
count: Number(cloudtentaclesForm.value.skuCount || 1),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchKnapsack() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('查询背包', () => fetchAdminCloudtentaclesKnapsack(buildCloudtentaclesTokenPayload()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchVnList() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('查询虚拟号列表', () => fetchAdminCloudtentaclesVnList({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
key: cloudtentaclesForm.value.vnKey.trim(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesAppointVn() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('申请虚拟号', async () => {
|
||||||
|
const response = await appointAdminCloudtentaclesVn({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
key: cloudtentaclesForm.value.vnKey.trim(),
|
||||||
|
})
|
||||||
|
const item = (response.data as { item?: { id?: number, phone?: string } }).item
|
||||||
|
if (item?.id) {
|
||||||
|
cloudtentaclesForm.value.vnId = Number(item.id)
|
||||||
|
}
|
||||||
|
if (item?.phone) {
|
||||||
|
cloudtentaclesForm.value.phone = String(item.phone)
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesGenerateVnLoginCode() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('生成登录码', () => generateAdminCloudtentaclesVnLoginCode({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
key: cloudtentaclesForm.value.vnKey.trim(),
|
||||||
|
id: Number(cloudtentaclesForm.value.vnId || 0),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchVnCode() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('获取验证码', async () => {
|
||||||
|
const response = await fetchAdminCloudtentaclesVnCode({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
key: cloudtentaclesForm.value.vnKey.trim(),
|
||||||
|
phone: cloudtentaclesForm.value.phone.trim(),
|
||||||
|
})
|
||||||
|
const code = (response.data as { code?: string }).code
|
||||||
|
if (code) {
|
||||||
|
cloudtentaclesForm.value.code = String(code)
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesVerifyVnCode() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('校验验证码', () => verifyAdminCloudtentaclesVnCode({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
key: cloudtentaclesForm.value.vnKey.trim(),
|
||||||
|
id: Number(cloudtentaclesForm.value.vnId || 0),
|
||||||
|
code: cloudtentaclesForm.value.code.trim(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCloudtentaclesFetchBindUrl() {
|
||||||
|
if (!ensureCloudtentaclesToken()) return
|
||||||
|
await runCloudtentaclesDebugAction('获取兑换链接', () => fetchAdminCloudtentaclesBindUrl({
|
||||||
|
...buildCloudtentaclesTokenPayload(),
|
||||||
|
key: cloudtentaclesForm.value.vnKey.trim(),
|
||||||
|
id: Number(cloudtentaclesForm.value.vnId || 0),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(loadConfigs)
|
onMounted(loadConfigs)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -631,6 +819,7 @@ onMounted(loadConfigs)
|
|||||||
type="button"
|
type="button"
|
||||||
:class="['platform-overview-card', { 'is-active': activePlatform === 'cloudtentacles' }]"
|
:class="['platform-overview-card', { 'is-active': activePlatform === 'cloudtentacles' }]"
|
||||||
@click="switchPlatform('cloudtentacles')"
|
@click="switchPlatform('cloudtentacles')"
|
||||||
|
v-if="isDevMode"
|
||||||
>
|
>
|
||||||
<div class="platform-head">
|
<div class="platform-head">
|
||||||
<span class="platform-badge">cloudtentacles</span>
|
<span class="platform-badge">cloudtentacles</span>
|
||||||
@@ -664,6 +853,7 @@ onMounted(loadConfigs)
|
|||||||
type="button"
|
type="button"
|
||||||
:class="['switch-chip', { 'is-active': activePlatform === 'cloudtentacles' }]"
|
:class="['switch-chip', { 'is-active': activePlatform === 'cloudtentacles' }]"
|
||||||
@click="switchPlatform('cloudtentacles')"
|
@click="switchPlatform('cloudtentacles')"
|
||||||
|
v-if="isDevMode"
|
||||||
>
|
>
|
||||||
cloudtentacles 履约平台
|
cloudtentacles 履约平台
|
||||||
</button>
|
</button>
|
||||||
@@ -1047,16 +1237,26 @@ onMounted(loadConfigs)
|
|||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else-if="isDevMode">
|
||||||
<section class="meta-card">
|
<section class="meta-card">
|
||||||
<div class="meta-line">
|
<div class="meta-line">
|
||||||
<span class="meta-label">配置文件</span>
|
<span class="meta-label">配置文件</span>
|
||||||
<code>{{ cloudtentaclesFilePath || '-' }}</code>
|
<code>{{ cloudtentaclesFilePath || '-' }}</code>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="meta-line">
|
||||||
|
<span class="meta-label">会话文件</span>
|
||||||
|
<code>{{ cloudtentaclesSessionFilePath || '-' }}</code>
|
||||||
|
</div>
|
||||||
<div class="meta-line">
|
<div class="meta-line">
|
||||||
<span class="meta-label">职责</span>
|
<span class="meta-label">职责</span>
|
||||||
<span>管理 cloudtentacles 外部履约平台的账号、短信验证码登录与 token 探活。该区域不处理订单来源同步。</span>
|
<span>管理 cloudtentacles 外部履约平台的账号、短信验证码登录与 token 探活。该区域不处理订单来源同步。</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="meta-line">
|
||||||
|
<span class="meta-label">已保存 token</span>
|
||||||
|
<span>
|
||||||
|
{{ cloudtentaclesPersistedSession?.hasToken ? `${cloudtentaclesPersistedSession.tokenMasked} / ${formatAdminDateTime(cloudtentaclesPersistedSession.loggedInAt)}` : '未保存' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="table-card">
|
<section class="table-card">
|
||||||
@@ -1099,6 +1299,26 @@ onMounted(loadConfigs)
|
|||||||
<input v-model="cloudtentaclesForm.code" class="text-input" placeholder="收到验证码后填写" />
|
<input v-model="cloudtentaclesForm.code" class="text-input" placeholder="收到验证码后填写" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label class="field-block">
|
||||||
|
<span>VN Key</span>
|
||||||
|
<input v-model="cloudtentaclesForm.vnKey" class="text-input" placeholder="例如 1" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="field-block">
|
||||||
|
<span>VN ID</span>
|
||||||
|
<input v-model.number="cloudtentaclesForm.vnId" class="text-input" type="number" min="0" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="field-block">
|
||||||
|
<span>SKU ID</span>
|
||||||
|
<input v-model.number="cloudtentaclesForm.skuId" class="text-input" type="number" min="0" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="field-block">
|
||||||
|
<span>购买数量</span>
|
||||||
|
<input v-model.number="cloudtentaclesForm.skuCount" class="text-input" type="number" min="1" />
|
||||||
|
</label>
|
||||||
|
|
||||||
<label class="field-block">
|
<label class="field-block">
|
||||||
<span>deviceId</span>
|
<span>deviceId</span>
|
||||||
<input v-model="cloudtentaclesForm.deviceId" class="text-input" placeholder="-" />
|
<input v-model="cloudtentaclesForm.deviceId" class="text-input" placeholder="-" />
|
||||||
@@ -1147,6 +1367,31 @@ onMounted(loadConfigs)
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="table-card">
|
||||||
|
<div class="section-title-row">
|
||||||
|
<div>
|
||||||
|
<h3>cloudtentacles 开发调试工具</h3>
|
||||||
|
<p>仅开发模式展示。用于调试分类、SKU、购买、背包、虚拟号和兑换链接链路。</p>
|
||||||
|
</div>
|
||||||
|
<div class="section-actions">
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesFetchAsset">余额</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesFetchCategories">分类</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesFetchSkuList">SKU</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesBuySku">购买</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesFetchKnapsack">背包</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesFetchVnList">虚拟号列表</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesAppointVn">申请虚拟号</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesGenerateVnLoginCode">生成登录码</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesFetchVnCode">获取验证码</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round @click="handleCloudtentaclesVerifyVnCode">校验验证码</el-button>
|
||||||
|
<el-button :loading="cloudtentaclesDebugLoading" round type="primary" @click="handleCloudtentaclesFetchBindUrl">兑换链接</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre v-if="cloudtentaclesDebugResult" class="debug-result">{{ cloudtentaclesDebugResult }}</pre>
|
||||||
|
<div v-else class="empty-inline">执行一次调试动作后,这里会显示原始返回数据。</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section v-if="cloudtentaclesLoginResult || cloudtentaclesValidateResult" class="table-card">
|
<section v-if="cloudtentaclesLoginResult || cloudtentaclesValidateResult" class="table-card">
|
||||||
<div class="section-title-row">
|
<div class="section-title-row">
|
||||||
<div>
|
<div>
|
||||||
@@ -1518,6 +1763,19 @@ onMounted(loadConfigs)
|
|||||||
color: #b42318;
|
color: #b42318;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.debug-result {
|
||||||
|
margin: 0;
|
||||||
|
padding: 14px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: #0f172a;
|
||||||
|
color: #e2e8f0;
|
||||||
|
overflow: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1100px) {
|
@media (max-width: 1100px) {
|
||||||
.overview-grid,
|
.overview-grid,
|
||||||
.result-grid,
|
.result-grid,
|
||||||
|
|||||||
Reference in New Issue
Block a user