polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
507 lines • 25.9 kB
JavaScript
"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