|
|
@@ -56,6 +56,8 @@ type ElementDemandItem = {
|
|
|
weight: number | null;
|
|
|
video_count: number | null;
|
|
|
video_list: string | null;
|
|
|
+ month_list?: string | null;
|
|
|
+ frequency?: number | null;
|
|
|
ext_info: string | null;
|
|
|
};
|
|
|
|
|
|
@@ -79,6 +81,25 @@ function parseVideoIdsFromList(raw: string | null): string[] {
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
+function formatYmDisplay(ym: string): string {
|
|
|
+ if (/^\d{6}$/.test(ym)) {
|
|
|
+ return `${ym.slice(0, 4)}-${ym.slice(4, 6)}`;
|
|
|
+ }
|
|
|
+ return ym;
|
|
|
+}
|
|
|
+
|
|
|
+function formatMonthListPreview(raw: string | null): string {
|
|
|
+ const months = parseVideoIdsFromList(raw);
|
|
|
+ if (months.length > 0) {
|
|
|
+ return `共 ${months.length} 个月,点击查看`;
|
|
|
+ }
|
|
|
+ const trimmed = (raw ?? "").trim();
|
|
|
+ if (!trimmed) {
|
|
|
+ return "-";
|
|
|
+ }
|
|
|
+ return trimmed.length > 36 ? `${trimmed.slice(0, 36)}…` : trimmed;
|
|
|
+}
|
|
|
+
|
|
|
const API_BASE_URL =
|
|
|
import.meta.env.VITE_API_BASE_URL ?? "/demand/api/v1";
|
|
|
|
|
|
@@ -652,6 +673,10 @@ function ElementDemandQueryPanel({
|
|
|
const [videoModalTitleName, setVideoModalTitleName] = useState("");
|
|
|
const [videoModalIds, setVideoModalIds] = useState<string[]>([]);
|
|
|
const [videoModalRaw, setVideoModalRaw] = useState("");
|
|
|
+ const [monthModalOpen, setMonthModalOpen] = useState(false);
|
|
|
+ const [monthModalTitleName, setMonthModalTitleName] = useState("");
|
|
|
+ const [monthModalMonths, setMonthModalMonths] = useState<string[]>([]);
|
|
|
+ const [monthModalRaw, setMonthModalRaw] = useState("");
|
|
|
const [decodeLoadingVid, setDecodeLoadingVid] = useState<string | null>(null);
|
|
|
|
|
|
const openVideoCmsDetail = useCallback((vid: string) => {
|
|
|
@@ -824,7 +849,8 @@ function ElementDemandQueryPanel({
|
|
|
}, [items, page, pageSize]);
|
|
|
|
|
|
const columns: ColumnsType<ElementDemandItem> = useMemo(
|
|
|
- () => [
|
|
|
+ () => {
|
|
|
+ const baseColumns: ColumnsType<ElementDemandItem> = [
|
|
|
{
|
|
|
title: "策略",
|
|
|
dataIndex: "strategy",
|
|
|
@@ -843,13 +869,8 @@ function ElementDemandQueryPanel({
|
|
|
width: 110,
|
|
|
render: (v) => (v === null || v === undefined ? "-" : String(v)),
|
|
|
},
|
|
|
- {
|
|
|
- title: "视频数",
|
|
|
- dataIndex: "video_count",
|
|
|
- width: 100,
|
|
|
- render: (v) => v ?? "-",
|
|
|
- },
|
|
|
- {
|
|
|
+ ];
|
|
|
+ const videoListColumn: ColumnsType<ElementDemandItem>[number] = {
|
|
|
title: "视频列表",
|
|
|
dataIndex: "video_list",
|
|
|
width: 220,
|
|
|
@@ -879,9 +900,53 @@ function ElementDemandQueryPanel({
|
|
|
</Typography.Link>
|
|
|
);
|
|
|
},
|
|
|
- },
|
|
|
- ],
|
|
|
- []
|
|
|
+ };
|
|
|
+ const videoCountColumn: ColumnsType<ElementDemandItem>[number] = {
|
|
|
+ title: "视频数",
|
|
|
+ dataIndex: "video_count",
|
|
|
+ width: 100,
|
|
|
+ render: (v) => v ?? "-",
|
|
|
+ };
|
|
|
+ if (mode === "monthly") {
|
|
|
+ baseColumns.push({
|
|
|
+ title: "频次",
|
|
|
+ dataIndex: "frequency",
|
|
|
+ width: 90,
|
|
|
+ render: (v) => (v === null || v === undefined ? "-" : String(v)),
|
|
|
+ });
|
|
|
+ baseColumns.push(videoCountColumn);
|
|
|
+ baseColumns.push({
|
|
|
+ title: "月份列表",
|
|
|
+ dataIndex: "month_list",
|
|
|
+ width: 180,
|
|
|
+ render: (_, record) => {
|
|
|
+ const raw = record.month_list ?? "";
|
|
|
+ const trimmed = raw.trim();
|
|
|
+ if (!trimmed) {
|
|
|
+ return "-";
|
|
|
+ }
|
|
|
+ const months = parseVideoIdsFromList(raw);
|
|
|
+ return (
|
|
|
+ <Typography.Link
|
|
|
+ onClick={() => {
|
|
|
+ setMonthModalTitleName(record.demand_name ?? "");
|
|
|
+ setMonthModalMonths(months);
|
|
|
+ setMonthModalRaw(raw);
|
|
|
+ setMonthModalOpen(true);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {formatMonthListPreview(raw)}
|
|
|
+ </Typography.Link>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ baseColumns.push(videoCountColumn);
|
|
|
+ }
|
|
|
+ baseColumns.push(videoListColumn);
|
|
|
+ return baseColumns;
|
|
|
+ },
|
|
|
+ [mode]
|
|
|
);
|
|
|
|
|
|
return (
|
|
|
@@ -1003,7 +1068,7 @@ function ElementDemandQueryPanel({
|
|
|
columns={columns}
|
|
|
dataSource={pagedItems}
|
|
|
pagination={false}
|
|
|
- scroll={{ x: 880 }}
|
|
|
+ scroll={{ x: mode === "monthly" ? 1150 : 880 }}
|
|
|
rowClassName={(_, index) => (index % 2 === 0 ? "row-even" : "row-odd")}
|
|
|
/>
|
|
|
</div>
|
|
|
@@ -1083,6 +1148,41 @@ function ElementDemandQueryPanel({
|
|
|
</Typography.Paragraph>
|
|
|
)}
|
|
|
</Modal>
|
|
|
+ <Modal
|
|
|
+ title={`月份列表${monthModalTitleName ? ` — ${monthModalTitleName}` : ""}`}
|
|
|
+ open={monthModalOpen}
|
|
|
+ onCancel={() => setMonthModalOpen(false)}
|
|
|
+ footer={
|
|
|
+ <Button type="primary" onClick={() => setMonthModalOpen(false)}>
|
|
|
+ 关闭
|
|
|
+ </Button>
|
|
|
+ }
|
|
|
+ width={560}
|
|
|
+ destroyOnHidden
|
|
|
+ >
|
|
|
+ {monthModalMonths.length > 0 ? (
|
|
|
+ <List
|
|
|
+ size="small"
|
|
|
+ bordered
|
|
|
+ dataSource={monthModalMonths}
|
|
|
+ style={{ maxHeight: 480, overflow: "auto" }}
|
|
|
+ renderItem={(ym, idx) => (
|
|
|
+ <List.Item style={{ paddingBlock: 10, paddingInline: 16 }}>
|
|
|
+ <Typography.Text copyable={{ text: ym }}>
|
|
|
+ {idx + 1}. {formatYmDisplay(ym)}
|
|
|
+ </Typography.Text>
|
|
|
+ </List.Item>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <Typography.Paragraph
|
|
|
+ copyable={{ text: monthModalRaw }}
|
|
|
+ style={{ marginBottom: 0, whiteSpace: "pre-wrap", wordBreak: "break-all" }}
|
|
|
+ >
|
|
|
+ {monthModalRaw || "(空)"}
|
|
|
+ </Typography.Paragraph>
|
|
|
+ )}
|
|
|
+ </Modal>
|
|
|
<div className="panel-footer">
|
|
|
<Pagination
|
|
|
current={page}
|