#47 合并

باز‌کردن
liulidong قصد ادغام 15 تغییر را از Web/master به Web/feature_260509_replace_upload_new_datasource دارد

+ 2 - 0
package.json

@@ -20,6 +20,7 @@
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
     "react-router-dom": "^6.23.1",
+    "uuid": "^14.0.1",
     "zustand": "^4.5.2"
   },
   "devDependencies": {
@@ -30,6 +31,7 @@
     "@types/node": "^22.14.0",
     "@types/react": "^18.3.3",
     "@types/react-dom": "^18.3.0",
+    "@types/uuid": "^11.0.0",
     "@typescript-eslint/parser": "^6.0.0",
     "@vitejs/plugin-react-swc": "^3.5.0",
     "autoprefixer": "^10.4.21",

+ 4 - 0
src/http/index.ts

@@ -1,4 +1,5 @@
 import axios from 'axios'
+import { v4 as uuidv4 } from 'uuid'
 import sso from './sso'
 import router from '@src/router/index'
 import type { AxiosInstance, CreateAxiosDefaults, AxiosRequestConfig } from 'axios'
@@ -21,6 +22,9 @@ class Request {
 				config.headers.token = userInfo.token
 			}
 
+			config.headers['X-Timestamp'] = Date.now().toString()
+			config.headers['X-Nonce'] = uuidv4()
+
       return config
     }, function(error) {
       return Promise.reject(error)

+ 15 - 1
src/views/publishContent/weCom/components/addPlanModal/index.tsx

@@ -121,10 +121,24 @@ const AddPlanModal: React.FC<{
 			</Form.Item>
 			<Form.Item label="发布内容" required>
 				<div className="flex flex-wrap gap-4 max-h-[660px] overflow-y-auto pr-2">
-						{selectedVideos.map((video) => (
+						{selectedVideos.map((video, index) => (
 							<Card
 								key={video.videoId}
 								className="w-[240px] relative group"
+								draggable
+								onDragStart={(e) => e.dataTransfer.setData('index', index.toString())}
+								onDragOver={(e) => e.preventDefault()}
+								onDrop={(e) => {
+									const fromIndex = parseInt(e.dataTransfer.getData('index'));
+									if (fromIndex !== index) {
+										setSelectedVideos(prev => {
+											const newVideos = [...prev];
+											const [draggedVideo] = newVideos.splice(fromIndex, 1);
+											newVideos.splice(index, 0, draggedVideo);
+											return newVideos;
+										});
+									}
+								}}
 							>
 								<Button
 									shape="circle"

+ 2 - 2
src/views/publishContent/weCom/components/videoSelectModal/index.tsx

@@ -31,7 +31,7 @@ const SHOW_DEMAND_HOVER = import.meta.env.MODE !== 'production' || getUserInfo()
 type LoadMode = 'replace' | 'append' | 'jump';
 
 const SOURCE_TABS: { key: string; label: string; disabled?: boolean }[] = [
-	{ key: '', label: '全部' },
+	// { key: '', label: '全部' },
 	{ key: 'prior', label: '粉丝喜欢' },
 	{ key: 'posterior', label: '已发优质相似' },
 	{ key: 'hot', label: '票圈热门' },
@@ -131,7 +131,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ visible, onClose, o
 	const [playingVideo, setPlayingVideo] = useState<WeVideoItem | null>(null);
 	const [viewingPage, setViewingPage] = useState(1);
 	const [pageAnchors, setPageAnchors] = useState<Map<number, number>>(new Map()); // videoId -> page
-	const [source, setSource] = useState<string>(''); // 测试入口:数据来源筛选(prior/posterior/hot/空)
+	const [source, setSource] = useState<string>('prior'); // 测试入口:数据来源筛选(prior/posterior/hot/空)
 	const observerRef = useRef<IntersectionObserver | null>(null);
 	const pageObserverRef = useRef<IntersectionObserver | null>(null);
 	const passedPagesRef = useRef<Set<number>>(new Set());

+ 16 - 2
src/views/publishContent/weGZH/components/publishPlanModal/index.tsx

@@ -285,10 +285,24 @@ const AddPunlishPlanModal: React.FC<AddPunlishPlanModalProps> = ({ visible, isSu
 						{ 
 							selectVideoType === 0 ?
 								(<div className="flex flex-wrap gap-4 max-h-[660px] overflow-y-auto pr-2">
-									{selectedVideos.map((video) => (
+									{selectedVideos.map((video, index) => (
 										<Card
 											key={video.videoId}
 											className="w-[240px] relative group"
+											draggable
+											onDragStart={(e) => e.dataTransfer.setData('index', index.toString())}
+											onDragOver={(e) => e.preventDefault()}
+											onDrop={(e) => {
+												const fromIndex = parseInt(e.dataTransfer.getData('index'));
+												if (fromIndex !== index) {
+													setSelectedVideos(prev => {
+														const newVideos = [...prev];
+														const [draggedVideo] = newVideos.splice(fromIndex, 1);
+														newVideos.splice(index, 0, draggedVideo);
+														return newVideos;
+													});
+												}
+											}}
 										>
 											<Button
 												shape="circle"
@@ -324,7 +338,7 @@ const AddPunlishPlanModal: React.FC<AddPunlishPlanModalProps> = ({ visible, isSu
 											</div>
 										</Card>
 									))}
-		
+
 									{/* Add Video Button - Conditionally Rendered */}
 									{selectedVideos.length < (planType === GzhPlanType.自动回复 ? 3 : 20) && (
 										<div

+ 2 - 2
src/views/publishContent/weGZH/components/videoSelectModal/index.tsx

@@ -35,7 +35,7 @@ const SHOW_DEMAND_HOVER = import.meta.env.MODE !== 'production' || getUserInfo()
 type LoadMode = 'replace' | 'append' | 'jump';
 
 const SOURCE_TABS: { key: string; label: string; disabled?: boolean }[] = [
-	{ key: '', label: '全部' },
+	// { key: '', label: '全部' },
 	{ key: 'prior', label: '粉丝喜欢' },
 	{ key: 'posterior', label: '已发优质相似' },
 	{ key: 'hot', label: '票圈热门' },
@@ -140,7 +140,7 @@ const VideoSelectModal: React.FC<VideoSelectModalProps> = ({ planType, visible,
 	const [playingVideo, setPlayingVideo] = useState<VideoItem | null>(null);
 	const [viewingPage, setViewingPage] = useState(1);
 	const [pageAnchors, setPageAnchors] = useState<Map<number, number>>(new Map()); // videoId -> page
-	const [source, setSource] = useState<string>(''); // 测试入口:数据来源筛选(prior/posterior/hot/空)
+	const [source, setSource] = useState<string>('prior'); // 测试入口:数据来源筛选(prior/posterior/hot/空)
 	const observerRef = useRef<IntersectionObserver | null>(null);
 	const pageObserverRef = useRef<IntersectionObserver | null>(null);
 	const passedPagesRef = useRef<Set<number>>(new Set());

+ 10 - 22
yarn.lock

@@ -1862,12 +1862,12 @@
   resolved "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz"
   integrity sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==
 
-"@types/xml-js@^1.0.0":
-  version "1.0.0"
-  resolved "https://registry.npmmirror.com/@types/xml-js/-/xml-js-1.0.0.tgz#f0535aea1cc126fb34fc0d0a278ca59997c899ee"
-  integrity sha512-tRJYQN/uAD8Br9K+pqqzJNd/htIxQaFy6ppfNEWbwsAoWRK3oAxzROCGA39GHT+E3BHLyuBnSB7XKsnJ0s4w2g==
+"@types/uuid@^11.0.0":
+  version "11.0.0"
+  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-11.0.0.tgz#f4fa34bbf2af941148ef1973c4361fc43617971c"
+  integrity sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==
   dependencies:
-    xml-js "*"
+    uuid "*"
 
 "@typescript-eslint/eslint-plugin@8.29.1":
   version "8.29.1"
@@ -2394,11 +2394,6 @@ cross-spawn@^7.0.2:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
-crypto-js@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
-  integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
-
 css-blank-pseudo@^7.0.1:
   version "7.0.1"
   resolved "https://registry.npmmirror.com/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz#32020bff20a209a53ad71b8675852b49e8d57e46"
@@ -5002,11 +4997,6 @@ safe-regex-test@^1.0.3:
   resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
 
-sax@^1.2.4:
-  version "1.4.1"
-  resolved "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
-  integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
-
 scheduler@^0.20.2:
   version "0.20.2"
   resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz"
@@ -5451,6 +5441,11 @@ util-deprecate@^1.0.2:
   resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
 
+uuid@*, uuid@^14.0.1:
+  version "14.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-14.0.1.tgz#8a5975b3e038902bfd169a10b5202f5ec0cf3faf"
+  integrity sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==
+
 vite-plugin-svgr@^4.3.0:
   version "4.3.0"
   resolved "https://registry.npmmirror.com/vite-plugin-svgr/-/vite-plugin-svgr-4.3.0.tgz#742f16f11375996306c696ec323e4d23f6005075"
@@ -5549,13 +5544,6 @@ wrappy@1:
   resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz"
   integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
 
-xml-js@*, xml-js@^1.6.11:
-  version "1.6.11"
-  resolved "https://registry.npmmirror.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9"
-  integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==
-  dependencies:
-    sax "^1.2.4"
-
 yallist@^3.0.2:
   version "3.1.1"
   resolved "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"