|
|
@@ -7,6 +7,7 @@ import {
|
|
|
Input,
|
|
|
InputNumber,
|
|
|
List,
|
|
|
+ message,
|
|
|
Modal,
|
|
|
Pagination,
|
|
|
Select,
|
|
|
@@ -87,6 +88,10 @@ const getResolvedApiBaseUrl = () => {
|
|
|
return new URL(API_BASE_URL, window.location.origin).toString();
|
|
|
};
|
|
|
|
|
|
+/** 票圈后台:视频详情页(新标签打开) */
|
|
|
+const CMS_VIDEO_POST_DETAIL_BASE =
|
|
|
+ "https://admin.piaoquantv.com/cms/post-detail/";
|
|
|
+
|
|
|
function DemandPoolPanel() {
|
|
|
const [strategies, setStrategies] = useState<string[]>([]);
|
|
|
const [dateRange, setDateRange] = useState<[Dayjs, Dayjs] | null>(() => {
|
|
|
@@ -550,6 +555,44 @@ function ElementDemandQueryPanel({
|
|
|
const [videoModalTitleName, setVideoModalTitleName] = useState("");
|
|
|
const [videoModalIds, setVideoModalIds] = useState<string[]>([]);
|
|
|
const [videoModalRaw, setVideoModalRaw] = useState("");
|
|
|
+ const [decodeLoadingVid, setDecodeLoadingVid] = useState<string | null>(null);
|
|
|
+
|
|
|
+ const openVideoCmsDetail = useCallback((vid: string) => {
|
|
|
+ const url = `${CMS_VIDEO_POST_DETAIL_BASE}${encodeURIComponent(vid)}/detail`;
|
|
|
+ window.open(url, "_blank", "noopener,noreferrer");
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const openVideoDecodePage = useCallback(async (vid: string) => {
|
|
|
+ setDecodeLoadingVid(vid);
|
|
|
+ try {
|
|
|
+ const resolvedBase = getResolvedApiBaseUrl();
|
|
|
+ const baseWithSlash = resolvedBase.endsWith("/")
|
|
|
+ ? resolvedBase
|
|
|
+ : `${resolvedBase}/`;
|
|
|
+ const url = new URL("videos/decode-url", baseWithSlash);
|
|
|
+ url.searchParams.set("vid", vid);
|
|
|
+ const response = await fetch(url.toString(), {
|
|
|
+ method: "GET",
|
|
|
+ headers: { Accept: "application/json" },
|
|
|
+ });
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP ${response.status}`);
|
|
|
+ }
|
|
|
+ const payload = (await response.json()) as { url2?: string | null };
|
|
|
+ const raw = payload.url2;
|
|
|
+ const trimmed =
|
|
|
+ typeof raw === "string" ? raw.trim() : raw != null ? String(raw).trim() : "";
|
|
|
+ if (!trimmed) {
|
|
|
+ message.warning("不存在解构页面");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ window.open(trimmed, "_blank", "noopener,noreferrer");
|
|
|
+ } catch {
|
|
|
+ message.error("解构页面地址查询失败");
|
|
|
+ } finally {
|
|
|
+ setDecodeLoadingVid(null);
|
|
|
+ }
|
|
|
+ }, []);
|
|
|
|
|
|
const buildQueryUrl = useCallback(() => {
|
|
|
const resolvedBase = getResolvedApiBaseUrl();
|
|
|
@@ -827,7 +870,7 @@ function ElementDemandQueryPanel({
|
|
|
关闭
|
|
|
</Button>
|
|
|
}
|
|
|
- width={720}
|
|
|
+ width={900}
|
|
|
destroyOnHidden
|
|
|
>
|
|
|
{videoModalIds.length > 0 ? (
|
|
|
@@ -837,11 +880,50 @@ function ElementDemandQueryPanel({
|
|
|
dataSource={videoModalIds}
|
|
|
style={{ maxHeight: 480, overflow: "auto" }}
|
|
|
renderItem={(vid, idx) => (
|
|
|
- <List.Item>
|
|
|
- <Typography.Text type="secondary" style={{ marginRight: 8 }}>
|
|
|
- {idx + 1}.
|
|
|
- </Typography.Text>
|
|
|
- <Typography.Text copyable>{vid}</Typography.Text>
|
|
|
+ <List.Item style={{ paddingBlock: 10, paddingInline: 16 }}>
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ display: "flex",
|
|
|
+ alignItems: "center",
|
|
|
+ width: "100%",
|
|
|
+ flexWrap: "nowrap",
|
|
|
+ gap: 12,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ style={{
|
|
|
+ display: "inline-flex",
|
|
|
+ alignItems: "baseline",
|
|
|
+ gap: "0.25em",
|
|
|
+ whiteSpace: "nowrap",
|
|
|
+ minWidth: 0,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Typography.Text type="secondary" style={{ margin: 0 }}>
|
|
|
+ {idx + 1}.
|
|
|
+ </Typography.Text>
|
|
|
+ <Typography.Text copyable={{ text: vid }} style={{ margin: 0 }}>
|
|
|
+ {vid}
|
|
|
+ </Typography.Text>
|
|
|
+ </span>
|
|
|
+ <Space size={4} style={{ marginLeft: "auto", flexShrink: 0 }}>
|
|
|
+ <Button
|
|
|
+ type="link"
|
|
|
+ size="small"
|
|
|
+ onClick={() => openVideoCmsDetail(vid)}
|
|
|
+ >
|
|
|
+ 查看视频详情
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ type="link"
|
|
|
+ size="small"
|
|
|
+ loading={decodeLoadingVid === vid}
|
|
|
+ onClick={() => void openVideoDecodePage(vid)}
|
|
|
+ >
|
|
|
+ 查看视频解构
|
|
|
+ </Button>
|
|
|
+ </Space>
|
|
|
+ </div>
|
|
|
</List.Item>
|
|
|
)}
|
|
|
/>
|