fix admin feature pricing visibility
This commit is contained in:
@@ -5,6 +5,12 @@ import { useGetIdentity } from "@refinedev/core";
|
||||
import { Button, Card, Form, Input, InputNumber, Modal, Select, Space, Table, Tag, Typography } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import {
|
||||
FEATURE_PRICING_OPTIONS,
|
||||
MODEL_TIER_OPTIONS,
|
||||
featurePricingLabel,
|
||||
modelTierLabel,
|
||||
} from "@/lib/admin/feature-pricing-labels";
|
||||
import { adminRequestJson } from "@/lib/admin/providers";
|
||||
|
||||
type Row = {
|
||||
@@ -19,8 +25,11 @@ type Row = {
|
||||
effectiveTo: string | null;
|
||||
};
|
||||
|
||||
const featureOptions = ["chat.standard", "chat.premium", "rectification", "report.full", "report.export", "profile.extra"];
|
||||
const tierOptions = ["standard", "premium", "internal"];
|
||||
const statusLabels: Record<string, string> = {
|
||||
draft: "草稿(draft)",
|
||||
published: "已发布(published)",
|
||||
retired: "已停用(retired)",
|
||||
};
|
||||
|
||||
export function FeaturePricingManagement() {
|
||||
const { data: identity } = useGetIdentity<{ permissions?: string[] }>();
|
||||
@@ -74,11 +83,11 @@ export function FeaturePricingManagement() {
|
||||
loading={isLoading}
|
||||
dataSource={rows}
|
||||
columns={[
|
||||
{ title: "功能", dataIndex: "featureKey" },
|
||||
{ title: "模型档位", dataIndex: "modelTier" },
|
||||
{ title: "功能", dataIndex: "featureKey", render: featurePricingLabel },
|
||||
{ title: "模型档位", dataIndex: "modelTier", render: modelTierLabel },
|
||||
{ title: "积分", dataIndex: "creditCost" },
|
||||
{ title: "版本", dataIndex: "version" },
|
||||
{ title: "状态", dataIndex: "status", render: (value: string) => <Tag color={value === "published" ? "green" : "default"}>{value}</Tag> },
|
||||
{ title: "状态", dataIndex: "status", render: (value: string) => <Tag color={value === "published" ? "green" : "default"}>{statusLabels[value] ?? value}</Tag> },
|
||||
{
|
||||
title: "操作",
|
||||
render: (_: unknown, row: Row) => (
|
||||
@@ -95,8 +104,8 @@ export function FeaturePricingManagement() {
|
||||
/>
|
||||
<Modal open={editing !== undefined} title={editing ? "编辑定价草稿" : "新建定价草稿"} onCancel={() => { setEditing(undefined); form.resetFields(); }} onOk={save} okButtonProps={{ disabled: !canWrite }}>
|
||||
<Form form={form} layout="vertical">
|
||||
<Form.Item name="featureKey" label="功能" rules={[{ required: true }]}><Select options={featureOptions.map((value) => ({ value, label: value }))} disabled={Boolean(editing)} /></Form.Item>
|
||||
<Form.Item name="modelTier" label="模型档位" rules={[{ required: true }]}><Select options={tierOptions.map((value) => ({ value, label: value }))} disabled={Boolean(editing)} /></Form.Item>
|
||||
<Form.Item name="featureKey" label="功能" rules={[{ required: true }]}><Select options={[...FEATURE_PRICING_OPTIONS]} disabled={Boolean(editing)} /></Form.Item>
|
||||
<Form.Item name="modelTier" label="模型档位" rules={[{ required: true }]}><Select options={[...MODEL_TIER_OPTIONS]} disabled={Boolean(editing)} /></Form.Item>
|
||||
<Form.Item name="creditCost" label="积分" rules={[{ required: true, type: "number", min: 1 }]}><InputNumber precision={0} min={1} style={{ width: "100%" }} /></Form.Item>
|
||||
<Form.Item name="reason" label="变更原因" rules={[{ required: true, min: 1, max: 500 }]}><Input /></Form.Item>
|
||||
</Form>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Alert, Button, Card, Col, Divider, InputNumber, Row, Space, Statistic, Table, Tag, Typography } from "antd";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { featurePricingLabel, modelTierLabel } from "@/lib/admin/feature-pricing-labels";
|
||||
import { adminRequestJson } from "@/lib/admin/providers";
|
||||
import {
|
||||
CONSULTATION_DOMAIN_DURATION_MS,
|
||||
@@ -132,8 +133,8 @@ export function PricingSimulator() {
|
||||
|
||||
<Card title="单功能表(p50)">
|
||||
<Table dataSource={rows} rowKey="key" pagination={false} scroll={{ x: 920 }} columns={[
|
||||
{ title: "功能", dataIndex: "featureKey" },
|
||||
{ title: "模型档位", render: (_, row) => row.pricing?.modelTier ?? <Tag>无发布配置</Tag> },
|
||||
{ title: "功能", dataIndex: "featureKey", render: featurePricingLabel },
|
||||
{ title: "模型档位", render: (_, row) => row.pricing ? modelTierLabel(row.pricing.modelTier) : <Tag>无发布配置</Tag> },
|
||||
{ title: "售价", render: (_, row) => row.estimate.saleCny === null ? "无发布价格" : `${row.pricing?.creditCost} 积分 / ${formatCny(row.estimate.saleCny)}` },
|
||||
{ title: "单位成本", render: (_, row) => row.estimate.source === "unavailable" ? <Tag>无实测数据</Tag> : <>{formatCny(row.estimate.costCny)}<Typography.Text type="secondary" style={{ display: "block" }}>{formatNumber(row.estimate.costMicrousd, " µUSD")} · {row.estimate.source === "ledger" ? "账本实测" : "模型估算"}</Typography.Text></> },
|
||||
{ title: "毛利率", render: (_, row) => row.estimate.marginPercent === null ? "需汇率或价格" : `${row.estimate.marginPercent.toFixed(1)}%` },
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
export const FEATURE_PRICING_OPTIONS = [
|
||||
{ value: "chat.standard", label: "标准咨询(chat.standard)" },
|
||||
{ value: "chat.premium", label: "高级咨询(chat.premium)" },
|
||||
{ value: "rectification", label: "生时校正(rectification)" },
|
||||
{ value: "report.full", label: "完整报告(report.full)" },
|
||||
{ value: "report.export", label: "报告导出(report.export)" },
|
||||
{ value: "profile.extra", label: "额外档案(profile.extra)" },
|
||||
] as const;
|
||||
|
||||
export const MODEL_TIER_OPTIONS = [
|
||||
{ value: "standard", label: "标准模型(standard)" },
|
||||
{ value: "premium", label: "高级模型(premium)" },
|
||||
{ value: "internal", label: "内部模型(internal)" },
|
||||
] as const;
|
||||
|
||||
export function featurePricingLabel(value: string) {
|
||||
return FEATURE_PRICING_OPTIONS.find((option) => option.value === value)?.label ?? value;
|
||||
}
|
||||
|
||||
export function modelTierLabel(value: string) {
|
||||
return MODEL_TIER_OPTIONS.find((option) => option.value === value)?.label ?? value;
|
||||
}
|
||||
@@ -194,6 +194,8 @@ const resourcePermissions: Record<string, { read: string; write?: string }> = {
|
||||
payments: { read: "billing.orders.read" },
|
||||
packages: { read: "billing.products.read", write: "billing.products.write" },
|
||||
products: { read: "billing.products.read", write: "billing.products.write" },
|
||||
"feature-pricing": { read: "billing.products.read", write: "billing.products.write" },
|
||||
"pricing-simulator": { read: "billing.products.read" },
|
||||
subscriptions: {
|
||||
read: "billing.orders.read",
|
||||
write: "billing.adjustments.write",
|
||||
|
||||
Reference in New Issue
Block a user