UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

507 lines 25.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProductHandler = void 0; const base_handler_1 = require("./base.handler"); const product_service_sdk_1 = require("../services/product.service.sdk"); const errors_1 = require("../utils/errors"); const confirmation_1 = require("../utils/confirmation"); const api_command_1 = require("../utils/api-command"); class ProductHandler extends base_handler_1.BaseHandler { constructor(authConfig, serviceConfig) { super(); this.productService = new product_service_sdk_1.ProductServiceSdk(authConfig, serviceConfig); } async listProducts(options = {}) { return this.executeWithErrorHandling(async () => { this.validateListOptions(options); const request = this.transformToListRequest(options); const products = await this.productService.listProducts(request); this.displayProductsList(products, request, options.output); }, 'product.list'); } validateListOptions(options) { const errors = []; if (options.page !== undefined) { if (typeof options.page !== 'number' || !Number.isInteger(options.page) || options.page < 1) { errors.push('page must be a positive integer (minimum 1)'); } } if (options.size !== undefined) { if (typeof options.size !== 'number' || !Number.isInteger(options.size) || options.size < 1 || options.size > 100) { errors.push('size must be an integer between 1 and 100'); } } if (options.channelId !== undefined) { if (typeof options.channelId !== 'string' || options.channelId.trim().length === 0) { errors.push('channelId must be a non-empty string'); } } if (options.output !== undefined && !['table', 'json'].includes(options.output)) { errors.push('output must be either "table" or "json"'); } if (errors.length > 0) { throw new errors_1.PolyVValidationError(`Product list options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed'); } } transformToListRequest(options) { return { ...(options.page !== undefined && { page: options.page }), ...(options.size !== undefined && { size: options.size }), ...(options.channelId !== undefined && { channelId: options.channelId }), ...(options.platform !== undefined && { platform: options.platform }) }; } displayProductsList(products, request, format = 'table') { const page = request.page || 1; const size = request.size || 20; if (products.length === 0) { if (request.platform) { this.displayInfo('No platform products found'); } else if (request.channelId) { this.displayInfo(`No products found for channel ${request.channelId}`); } else { this.displayInfo('No products found'); } return; } const fromItem = (page - 1) * size + 1; const toItem = Math.min(fromItem + products.length - 1, fromItem + size - 1); this.displayInfo(`Showing products ${fromItem}-${toItem} (page ${page}, size ${size})`); if (request.platform) { this.displayInfo('Platform products (user-level product library)'); } else if (request.channelId) { this.displayInfo(`Filtered by channel: ${request.channelId}`); } if (format === 'json') { this.displayData(products, 'json'); } else { this.displayProductsTable(products, request.platform); } } displayProductsTable(products, isPlatform) { const tableData = products.map(product => { const row = { 'Product ID': product.productId, }; if (!isPlatform) { row['Channel ID'] = product.channelId; } row['Name'] = product.name; row['Type'] = this.formatProductType(product.productType); if (!isPlatform) { row['Status'] = this.formatProductStatus(product.status); } row['Price'] = this.formatPrice(product.price, product.realPrice); row['Created'] = product.createdAt.toLocaleDateString(); row['Updated'] = product.updatedAt.toLocaleDateString(); return row; }); this.displayAsTable(tableData); } formatProductType(type) { const typeMap = { 'normal': 'Normal', 'finance': 'Finance', 'position': 'Position' }; return typeMap[type] || type; } formatProductStatus(status) { const statusMap = { 1: '上架', 2: '下架' }; return statusMap[status] || `Status ${status}`; } formatPrice(price, realPrice) { if (price === undefined && realPrice === undefined) { return '-'; } if (price !== undefined && realPrice !== undefined && price !== realPrice) { return `¥${realPrice} (was ¥${price})`; } const displayPrice = realPrice !== undefined ? realPrice : price; return `¥${displayPrice}`; } async addProduct(options) { return this.executeWithErrorHandling(async () => { const result = await this.productService.addProduct(options); this.displayAddResult(result, options.output); }, 'product.add'); } displayAddResult(result, format) { const data = { productId: result.productId, name: result.name, channelId: result.channelId, created: new Date(result.createdTime).toISOString() }; if (format === 'json') { this.displayData(data, 'json'); } else { this.displaySuccess(`Product created successfully`, data, 'table'); } } async updateProduct(options) { return this.executeWithErrorHandling(async () => { await this.productService.updateProduct(options); this.displayUpdateResult(options, options.output); }, 'product.update'); } displayUpdateResult(options, format) { const data = { productId: options.productId, channelId: options.channelId, name: options.name, status: options.status === 1 ? 'Active' : 'Inactive', updated: new Date().toISOString() }; if (format === 'json') { this.displayData(data, 'json'); } else { this.displaySuccess(`Product updated successfully`, data, 'table'); } } async deleteProduct(options) { return this.executeWithErrorHandling(async () => { if (!options.force) { const confirmed = await (0, confirmation_1.confirmDeletion)(`确定要删除商品 ${options.productId} 吗?此操作不可撤销。`, 'yes'); if (!confirmed) { this.displayInfo('操作已取消'); return; } } await this.productService.deleteProduct(options); this.displayDeleteResult(options, options.output); }, 'product.delete'); } displayDeleteResult(options, format) { const data = { productId: options.productId, channelId: options.channelId, deleted: true, timestamp: new Date().toISOString() }; if (format === 'json') { this.displayData(data, 'json'); } else { this.displaySuccess(`Product ${options.productId} deleted successfully`, data, 'table'); } } async listUserProducts(options = {}) { return this.executeWithErrorHandling(async () => { const result = await this.productService.listUserProducts(options); this.displayData(result, options.output || 'table'); }, 'product.library.list'); } async createUserProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['name', 'linkType', 'link']); await (0, api_command_1.confirmWrite)(options.force, `Create user product "${options.name}"?`); const result = await this.productService.createUserProduct(options); this.displayWriteResult('User product created successfully', { productId: result }, options.output); }, 'product.library.create'); } async updateUserProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['productId', 'name', 'linkType', 'link']); await (0, api_command_1.confirmWrite)(options.force, `Update user product ${options.productId}?`); await this.productService.updateUserProduct(options); this.displayWriteResult('User product updated successfully', { productId: options.productId }, options.output); }, 'product.library.update'); } async deleteUserProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['productId']); await (0, api_command_1.confirmWrite)(options.force, `Delete user product ${options.productId}?`); await this.productService.deleteUserProduct(options); this.displayWriteResult('User product deleted successfully', { productId: options.productId }, options.output); }, 'product.library.delete'); } async listProductTags(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); const result = await this.productService.listProductTags(options); this.displayData(result, options.output || 'table'); }, 'product.tag.list'); } async createProductTag(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['name']); await (0, api_command_1.confirmWrite)(options.force, `Create product tag "${options.name}"?`); const result = await this.productService.createProductTag(options); this.displayWriteResult('Product tag created successfully', result, options.output); }, 'product.tag.create'); } async updateProductTag(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['id', 'name']); await (0, api_command_1.confirmWrite)(options.force, `Update product tag ${options.id}?`); await this.productService.updateProductTag(options); this.displayWriteResult('Product tag updated successfully', { id: options.id, name: options.name }, options.output); }, 'product.tag.update'); } async deleteProductTag(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['id']); await (0, api_command_1.confirmWrite)(options.force, `Delete product tag ${options.id}?`); await this.productService.deleteProductTag(options); this.displayWriteResult('Product tag deleted successfully', { id: options.id }, options.output); }, 'product.tag.delete'); } async listProductOrders(options = {}) { return this.executeWithErrorHandling(async () => { const result = await this.productService.listProductOrders(options); this.displayData(result, options.output || 'table'); }, 'product.order.list'); } async getProductOrder(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['orderNo']); const result = await this.productService.getProductOrder(options); this.displayData(result, options.output || 'table'); }, 'product.order.get'); } async batchUpdateProductOrderStatus(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['orderNos', 'status']); await (0, api_command_1.confirmWrite)(options.force, `Update status for product orders ${options.orderNos}?`); const result = await this.productService.batchUpdateProductOrderStatus(options); this.displayWriteResult('Product order status updated successfully', result, options.output); }, 'product.order.batchStatus'); } async getChannelProductEnabled(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); const result = await this.productService.getChannelProductEnabled(options.channelId); this.displayData(result, options.output || 'table'); }, 'product.enabled.get'); } async updateChannelProductEnabled(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'enabled']); this.validateYn(options.enabled, 'enabled'); await (0, api_command_1.confirmWrite)(options.force, `Update channel product library switch for channel ${options.channelId}?`); await this.productService.updateChannelProductEnabled({ channelId: options.channelId, enabled: options.enabled, }); this.displayWriteResult('Channel product library switch updated successfully', { channelId: options.channelId, enabled: options.enabled, }, options.output); }, 'product.update-enabled'); } async batchAddChannelProducts(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'products']); await (0, api_command_1.confirmWrite)(options.force, `Add ${options.products.length} product(s) to channel ${options.channelId}?`); const result = await this.productService.batchAddChannelProducts({ channelId: options.channelId, products: options.products, }); this.displayWriteResult('Channel products added successfully', result, options.output); }, 'product.batch-add'); } async batchDeleteChannelProducts(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productIds']); await (0, api_command_1.confirmWrite)(options.force, `Delete product(s) ${options.productIds.join(',')} from channel ${options.channelId}?`); const result = await this.productService.batchDeleteChannelProducts({ channelId: options.channelId, productIds: options.productIds, }); this.displayWriteResult('Channel products deleted successfully', result, options.output); }, 'product.batch-delete'); } async batchShelfChannelProducts(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productIds', 'shelf']); await (0, api_command_1.confirmWrite)(options.force, `Update shelf status for product(s) ${options.productIds.join(',')}?`); const result = await this.productService.batchShelfChannelProducts({ channelId: options.channelId, productIds: options.productIds, shelf: options.shelf, }); this.displayWriteResult('Channel products shelf status updated successfully', result, options.output); }, 'product.batch-shelf'); } async shelfChannelProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId', 'shelf']); await (0, api_command_1.confirmWrite)(options.force, `Update shelf status for product ${options.productId}?`); const result = await this.productService.shelfChannelProduct(options); this.displayWriteResult('Channel product shelf status updated successfully', result, options.output); }, 'product.shelf'); } async sortChannelProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId', 'type']); await (0, api_command_1.confirmWrite)(options.force, `Sort product ${options.productId} in channel ${options.channelId}?`); const result = await this.productService.sortChannelProduct(options); this.displayWriteResult('Channel product sorted successfully', result, options.output); }, 'product.sort'); } async pushChannelProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId']); await (0, api_command_1.confirmWrite)(options.force, `Push product ${options.productId} to viewers?`); const result = await this.productService.pushChannelProduct(options); this.displayWriteResult('Channel product pushed successfully', result, options.output); }, 'product.push'); } async cancelPushChannelProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId']); await (0, api_command_1.confirmWrite)(options.force, `Cancel pushed product ${options.productId}?`); const result = await this.productService.cancelPushChannelProduct(options); this.displayWriteResult('Channel product push cancelled successfully', result, options.output); }, 'product.cancel-push'); } async referenceProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'originId', 'status']); await (0, api_command_1.confirmWrite)(options.force, `Reference platform product ${options.originId} into channel ${options.channelId}?`); const result = await this.productService.referenceProduct(options); this.displayWriteResult('Platform product referenced successfully', result, options.output); }, 'product.reference'); } async getProductPushRule(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); const result = await this.productService.getProductPushRule({ channelId: options.channelId }); this.displayData(result, options.output || 'table'); }, 'product.push-rule.get'); } async updateProductPushRule(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); this.requireAtLeastOne(options, [ 'productExplainEnabled', 'productExplainingAutoPushAndSticky', 'productListSortType', 'productTagSortType', 'productPushRule', 'productHotEffectEnabled', 'normalProductHotEffectTips', 'jobProductHotEffectTips', 'financeProductHotEffectTips', 'outLinkProductRedirectEnabled', 'productTagSortOrderIds', ]); await (0, api_command_1.confirmWrite)(options.force, `Update product push rule for channel ${options.channelId}?`); await this.productService.updateProductPushRule(options); this.displayWriteResult('Product push rule updated successfully', { channelId: options.channelId }, options.output); }, 'product.push-rule.update'); } async listChannelProductTags(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); const result = await this.productService.listChannelProductTags(options); this.displayData(result, options.output || 'table'); }, 'product.channel-tag.list'); } async createChannelProductTag(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'name']); await (0, api_command_1.confirmWrite)(options.force, `Create channel product tag "${options.name}" in channel ${options.channelId}?`); const result = await this.productService.createChannelProductTag(options); this.displayWriteResult('Channel product tag created successfully', result, options.output); }, 'product.channel-tag.create'); } async updateChannelProductTag(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'id', 'name']); await (0, api_command_1.confirmWrite)(options.force, `Update channel product tag ${options.id} in channel ${options.channelId}?`); await this.productService.updateChannelProductTag(options); this.displayWriteResult('Channel product tag updated successfully', { channelId: options.channelId, id: options.id, name: options.name }, options.output); }, 'product.channel-tag.update'); } async deleteChannelProductTag(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'id']); await (0, api_command_1.confirmWrite)(options.force, `Delete channel product tag ${options.id} from channel ${options.channelId}?`); await this.productService.deleteChannelProductTag(options); this.displayWriteResult('Channel product tag deleted successfully', { channelId: options.channelId, id: options.id }, options.output); }, 'product.channel-tag.delete'); } async listProductStats(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); const result = await this.productService.listProductStats(options); this.displayData(result, options.output || 'table'); }, 'product.stats.list'); } async getProductStatsSummary(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId']); const result = await this.productService.getProductStatsSummary(options); this.displayData(result, options.output || 'table'); }, 'product.stats.summary'); } async sortChannelProductRank(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId', 'rank']); await (0, api_command_1.confirmWrite)(options.force, `Set product ${options.productId} rank to ${options.rank} in channel ${options.channelId}?`); await this.productService.sortChannelProductRank(options); this.displayWriteResult('Channel product rank updated successfully', { channelId: options.channelId, productId: options.productId, rank: options.rank }, options.output); }, 'product.rank'); } async toppingChannelProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId']); await (0, api_command_1.confirmWrite)(options.force, `Top product ${options.productId} in channel ${options.channelId}?`); await this.productService.toppingChannelProduct(options); this.displayWriteResult('Channel product topped successfully', { channelId: options.channelId, productId: options.productId }, options.output); }, 'product.topping'); } async untoppingChannelProduct(options) { return this.executeWithErrorHandling(async () => { this.requireFields(options, ['channelId', 'productId']); await (0, api_command_1.confirmWrite)(options.force, `Untop product ${options.productId} in channel ${options.channelId}?`); await this.productService.untoppingChannelProduct(options); this.displayWriteResult('Channel product untopped successfully', { channelId: options.channelId, productId: options.productId }, options.output); }, 'product.untopping'); } displayWriteResult(message, data, output) { if (output === 'json') { this.displayData({ success: true, data }, 'json'); } else { this.displaySuccess(message, data, 'table'); } } requireFields(options, fields) { const record = options; const missing = fields.filter((field) => { const value = record[field]; return value === undefined || value === null || value === ''; }); if (missing.length > 0) { throw new errors_1.PolyVValidationError(`Missing required option(s): ${missing.join(', ')}`, 'options', options, 'validation_failed'); } } validateYn(value, fieldName) { if (value !== 'Y' && value !== 'N') { throw new errors_1.PolyVValidationError(`${fieldName} must be Y or N`, fieldName, value, 'invalid_value'); } } requireAtLeastOne(options, fields) { const present = fields.some((field) => { const value = options[field]; return value !== undefined && value !== null && value !== ''; }); if (!present) { throw new errors_1.PolyVValidationError(`At least one option is required: ${fields.join(', ')}`, 'options', options, 'validation_failed'); } } } exports.ProductHandler = ProductHandler; //# sourceMappingURL=product.handler.js.map