xiebaomin 1 년 전
부모
커밋
0328974d1e

+ 3 - 1
components.d.ts

@@ -25,8 +25,10 @@ declare module 'vue' {
     VanField: typeof import('vant/es')['Field']
     VanForm: typeof import('vant/es')['Form']
     VanHighlight: typeof import('vant/es')['Highlight']
+    VanIcon: typeof import('vant/es')['Icon']
     VanImage: typeof import('vant/es')['Image']
-    VanImagePreview: typeof import('vant/es')['ImagePreview']
+    VanRadio: typeof import('vant/es')['Radio']
+    VanRadioGroup: typeof import('vant/es')['RadioGroup']
     VanSearch: typeof import('vant/es')['Search']
     VanSwipe: typeof import('vant/es')['Swipe']
     VanSwipeItem: typeof import('vant/es')['SwipeItem']

+ 2 - 1
index.html

@@ -3,7 +3,8 @@
   <head>
     <meta charset="UTF-8" />
     <meta name="referrer" content="never">
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <meta name="pdf" content="none">
+    <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1" />
     <title>内容库</title>

BIN
public/favicon.ico


+ 0 - 1
public/vite.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

+ 3 - 1
src/Hooks/useCopyText.ts

@@ -1,7 +1,9 @@
 import { showNotify } from 'vant';
+import { statisticAddContext } from '@/api/context/context';
 
-const useCopyText = (text: string) => {
+const useCopyText = async (text: string, authorId: string) => {
     if (navigator.clipboard && window.isSecureContext) { // 判断浏览器支持Clipboard API并且页面运行在安全上下文中
+        await statisticAddContext({ type: 1, authorId })
         navigator.clipboard.writeText(text); // 将文本内容复制到剪贴板
         showNotify('已成功复制!'); // 提示复制成功信息
     } else {

+ 15 - 0
src/Hooks/useCreateWebShareCard.ts

@@ -0,0 +1,15 @@
+const createWebShareCard = (obj: { title: string, description: string, image: string } & Record<string, string>) => {
+	const head = document.querySelector('head') as HTMLHeadElement;
+
+	for (const key in obj) {
+		const meta = document.createElement('meta') as HTMLMetaElement;
+
+		// 设置属性值
+		meta.setAttribute('property', `og:${key}`); // 设置 name 属性为 description
+		meta.setAttribute('content', obj[key]); // 设置 content 属性为指定内容
+		head.appendChild(meta);
+	}
+
+}
+
+export default createWebShareCard

+ 61 - 47
src/Hooks/usePermission/permiMode.tsx

@@ -1,54 +1,64 @@
 import { ComponentOptions, defineComponent, ref } from 'vue'
 import type { IPermiObj } from './type'
 import { css } from '@emotion/css'
-import 'vant/lib/index.css';
-import { Button } from 'vant';
-import { useRoute } from 'vue-router';
+import 'vant/lib/index.css'
+import { Button } from 'vant'
+import { useRoute } from 'vue-router'
 
 const MyComponent = (prop: IPermiObj | Boolean): ComponentOptions =>
 	defineComponent({
 		name: 'MyComponent',
 		components: {
-			[Button.name as string]: Button
+			[Button.name as string]: Button,
 		},
 		setup() {
 			const obj = prop as IPermiObj
 			const FixDivMode = css`
-				width: 100vw;
-				height: 100vh;
-				position: fixed;
-				left: 0;
-				top: 0;
-				overflow: hidden;
-				z-index: 999999;
-			`
+    width: 100vw;
+    height: 100vh;
+    position: fixed;
+    left: 0;
+    top: 0;
+    overflow: hidden;
+    z-index: 999999;
+   `
 			const FixUpperLevels = css`
-				width: 100%;
-				height: 185px;
-				background: linear-gradient(180deg, rgba(255,255,255,0.5) 0%, #FFFFFF 100%);
-			`
+    width: 100%;
+    height: 185px;
+    background: linear-gradient(180deg, rgba(255, 255, 255, 0.5) 0%, #ffffff 100%);
+   `
 			const FixTips = css`
-				font-size: 14px;
-				text-align: center;
-				width: 100%;
-				color: #666666;
-				height: calc(100vh - 185px);
-				background: #fff;
-				padding-top: 138px;
-				box-sizing: border-box;
-			`
+    font-size: 14px;
+    text-align: center;
+    width: 100%;
+    color: #666666;
+    height: calc(100vh - 185px);
+    background: #fff;
+    padding-top: 138px;
+    box-sizing: border-box;
+   `
 			const FixBtn = css`
-				font-size: 13px;
-				margin-top: 15px;
-				width: 315px;
-				height: 42px;
-				white-space: nowrap;
-				background-color: #FF5B00;
-				color: #FFF;
-			`
+    font-size: 13px;
+    margin-top: 15px;
+    width: 315px;
+    height: 42px;
+    white-space: nowrap;
+    background-color: #ff5b00;
+    color: #fff;
+   `
 			const route = useRoute()
 			const handleClick = () => {
-				window.location.href = import.meta.env.VITE_HTTP_URL + obj.redirect + '?t=' + route.query.t + '&isDataBase=' + 1 + '&spId=' + route.query.spId + '&id=' + route.query.id
+				window.location.href =
+					import.meta.env.VITE_HTTP_URL +
+					obj.redirect +
+					'?t=' +
+					route.query.t +
+					'&isDataBase=' +
+					1 +
+					'&spId=' +
+					route.query.spId +
+					'&id=' +
+					route.query.id
 			}
 			const pageLocation = ref<number>(0)
 			const stop = () => {
@@ -57,8 +67,8 @@ const MyComponent = (prop: IPermiObj | Boolean): ComponentOptions =>
 				document.body.style.top = '-' + pageLocation.value + 'px'
 			}
 			const move = () => {
-				document.body.style.position = 'static';
-    		window.scrollTo(0, pageLocation.value);
+				document.body.style.position = 'static'
+				window.scrollTo(0, pageLocation.value)
 			}
 			return {
 				FixTips,
@@ -68,22 +78,26 @@ const MyComponent = (prop: IPermiObj | Boolean): ComponentOptions =>
 				handleClick,
 				obj,
 				stop,
-				move
+				move,
 			}
 		},
 		render() {
 			prop ? this.stop() : this.move()
-			return prop && <div class={this.FixDivMode}>
-				<div class={this.FixUpperLevels}></div>
-				<div class={this.FixTips}>
-					<div>
-						{this.obj.text}
+			return (
+				prop && (
+					<div class={this.FixDivMode}>
+						<div class={this.FixUpperLevels}></div>
+						<div class={this.FixTips}>
+							<div>{this.obj.text}</div>
+							<div>
+								<van-button class={this.FixBtn} onClick={this.handleClick}>
+									{this.obj.btnText}
+								</van-button>
+							</div>
+						</div>
 					</div>
-					<div>
-						<van-button class={this.FixBtn} onClick={this.handleClick}>{this.obj.btnText}</van-button>
-					</div>
-				</div>
-			</div>
+				)
+			)
 		},
 	})
 

+ 28 - 1
src/Hooks/useStopWindowContext.ts

@@ -1,4 +1,4 @@
-const useStopWindowContext = () => {
+const useStopWindowContext = (uid: number) => {
 	
 	// 监听键盘事件
 	window.addEventListener('keydown', function(event) {
@@ -8,7 +8,34 @@ const useStopWindowContext = () => {
 	});
 
 	window.addEventListener("keydown", ev => ev.key === "F12" && ev.preventDefault())
+	console.log(uid)
 
+	uid && document.body.addEventListener(
+		"touchstart",
+		(e) => {
+			e.preventDefault();
+		},
+		{ passive: false }
+	);
+	window.addEventListener('beforeprint', function() {
+		// 在打印或生成 PDF 前的操作
+		const noPrintElements = document.querySelectorAll('.no-print');
+		for (var i = 0; i < noPrintElements.length; i++) {
+			(noPrintElements[i] as HTMLElement).style.display = 'none';
+		}
+	});
+	
+	window.addEventListener('afterprint', function() {
+		// 在打印或生成 PDF 后的操作
+		const noPrintElements = document.querySelectorAll('.no-print');
+		for (var i = 0; i < noPrintElements.length; i++) {
+			(noPrintElements[i] as HTMLElement).style.display = '';
+		}
+	});
+
+	document.addEventListener('selectstart', (event) => {
+		event.preventDefault();
+	});
 	// 监听鼠标右键事件
 	window.addEventListener('contextmenu', function(event) {
 		event.preventDefault(); // 阻止默认行为

+ 1 - 1
src/Hooks/useWeChatShare.ts

@@ -27,7 +27,7 @@ export type shareParams = {
 	imageUrl?: string
 	isShowToast?: boolean
 }
-const shareOptions: shareOptions[] = [
+export const shareOptions: shareOptions[] = [
 	{
 		type: '1',
 		imageUrl: '',

+ 4 - 0
src/api/context/context.ts

@@ -12,6 +12,7 @@ import type {
 	DShareConfigResultData,
 	IStatistics,
 	DPreviewResultData,
+	IContextAddRequest
 } from '@/types/api/context.type'
 import { requestGET, requestPOST } from '@/types/api/index'
 import { DForm } from '@/types/views/add.type'
@@ -37,6 +38,9 @@ export const setStatistics = (data: IStatistics) =>
 export const addAllStatusForm = (data: DForm) =>
 	requestPOST<ContextRequest, { data: string }>('/commodity/product/archive/add', data)
 
+export const statisticAddContext = (data: IContextAddRequest) =>
+	requestGET<ContextRequest, { data: string }>('/commodity/statistics/addPv', data)
+
 export const previewData = (params: IPreviewRequest) => {
 	return new Promise<DPreviewResultData>((resolve, reject) => {
 		const { userId, type, id } = params

BIN
src/assets/favicon.ico


+ 0 - 1
src/assets/vue.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 3 - 0
src/components/data-button/data-button.vue

@@ -40,6 +40,9 @@ const handleClick = (): void => {
   color: #ffffff;
 }
 :deep() {
+  .van-button {
+    border-radius: 1px;
+  }
   .van-button:before {
 		background: none;
 		border: none;

+ 1 - 19
src/components/image-preview/image-preview.vue

@@ -11,25 +11,7 @@
 
 <script setup lang="ts">
 import { IImagePreviewList } from "./index.type";
-withDefaults(defineProps<IImagePreviewList>(), {
-	urls: () => [
-		'https://fastly.jsdelivr.net/npm/@vant/assets/apple-1.jpeg',
-    'https://fastly.jsdelivr.net/npm/@vant/assets/apple-2.jpeg',
-	]
-})
-
-//const urls = [
-//  "https://fastly.jsdelivr.net/npm/@vant/assets/apple-1.jpeg",
-//  "https://fastly.jsdelivr.net/npm/@vant/assets/apple-2.jpeg",
-//];
-
-document.body.addEventListener(
-  "touchstart",
-  (e) => {
-		e.preventDefault();
-  },
-  { passive: false }
-);
+defineProps<IImagePreviewList>()
 </script>
 
 <style scoped lang="scss">

+ 3 - 0
src/components/pdf-preview/index.ts

@@ -0,0 +1,3 @@
+// start:ng42.barrel
+// end:ng42.barrel
+

+ 0 - 7
src/components/pdf-preview/pdf-preview.vue

@@ -33,13 +33,6 @@ const initPDF = () => {
         state.numPages = pdf.numPages;
       })
 };
-document.body.addEventListener(
-  "touchstart",
-  (e) => {
-		e.preventDefault();
-  },
-  { passive: false }
-);
 onMounted(() => {
 	initPDF()
 })

+ 0 - 3
src/components/video-preview/video-preview.vue

@@ -21,9 +21,6 @@ import { ref, reactive, onMounted } from "vue";
 import { IProps, IVideoOptions } from "./index.type";
 import "video.js/dist/video-js.css";
 import useBlobFile from "@/Hooks/useBlob";
-import useStopWindowContext from '@/Hooks/useStopWindowContext';
-
-useStopWindowContext()
 
 const props = defineProps<IProps>();
 

+ 6 - 0
src/types/api/context.type.ts

@@ -65,6 +65,7 @@ export type IPreviewForm = {
 	waters: Array<string> | string
 	productId: string
 	id?: string
+	image: string
 }
 export type DPreviewResultData = IResultData<IPreviewForm>
 export interface ILabelKeyRequest extends IGlobalListRequest { // 参数
@@ -89,6 +90,10 @@ export interface IArchiveRequest { // 参数
 
 export type IArchiveListRequest = IArchiveRequest & Partial<IGlobalListRequest>
 
+export type IContextAddRequest = {
+	type: 1
+	authorId: string
+}
 export interface IStoreRequest extends IGlobalListRequest {
 	productName: string,
 	shopName?: string
@@ -135,4 +140,5 @@ export interface ContextRequest {
 	'/user/record/Statistics': IStatistics
 	'/commodity/product/archive/add': DForm
 	'/home/findKeyWordList': INewLabelKeyRequest
+	'/commodity/statistics/addPv': IContextAddRequest
 }

+ 49 - 3
src/types/views/database.type.ts

@@ -1,15 +1,18 @@
+import { reactive } from "vue";
 import { DArchiveResultData, IArchiveRequest } from "../api/context.type";
 
 export type DMenu = {
 	text: string;
 	value: number;
+  subtitle?: string;
 }
 
 export interface DMenuList<T> {
 	type: 'Double' | 'Singular'
 	changeValue?: number
-	options: Array<T>
+	options: Array<T & any>
 	title: string
+  isSearch?: boolean
 }
 
 export type ChangeEmitParams = {
@@ -69,7 +72,50 @@ export const tabList: Array<DScrollTab> = [
     text: "百科",
   },
 ]
-
+export const menuTypeOptions = reactive<Array<DMenuList<DMenu>>>([
+  {
+    type: "Double",
+    title: "标签",
+    options: [],
+  },
+  {
+    type: "Singular",
+    title: "商品",
+    changeValue: 0,
+    options: [],
+  },
+  {
+    type: "Singular",
+    title: "用户阶段",
+    changeValue: 0,
+    options: [
+      {
+        text: "用户阶段(全部)",
+        value: 0,
+      },
+      {
+        text: "认知阶段<span>(仅浏览过或咨询过一次该商品的用户)</span>",
+        subtitle: "",
+        value: 1,
+      },
+      {
+        text: "兴趣阶段<span>(已咨询过该商品,且有过多次浏览搜索该商品的用户)</span>",
+        subtitle: "",
+        value: 2,
+      },
+      {
+        text: "决策阶段<span>(多次询问商品且与同类商品比价,想要体验该商品的用户)</span>",
+        subtitle: "",
+        value: 3,
+      },
+      {
+        text: "购买阶段<span>(正在走采购流程或已经将商品加入购物车的用户)</span>",
+        subtitle: "",
+        value: 4,
+      },
+    ],
+  },
+]);
 export type IAllStatus = {
   allStatus: '1' | '2'
   value: '企业话术' | '个人话术'
@@ -89,6 +135,7 @@ export interface DEmit {
 
 export interface DDataBaseListAll {
   type: ChangeTabEmit
+  showMore: boolean
   dataList: DArchiveResultData[]
 }
 
@@ -98,4 +145,3 @@ export type DFindArgs<T> = T extends ((e: any, n: infer R) => any) ? R : never
 
 export type DFindParams<T, K extends keyof T> = T[K]
 
-export type DFindPartialParams<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

+ 3 - 4
src/views/Database/components/context-contain.vue

@@ -39,15 +39,14 @@ const router = useRouter()
 const pageNum = ref<number>(1);
 const emit = defineEmits<DEmit>();
 
-const props = defineProps<DDataBaseListAll & { showMore: boolean }>()
+const props = defineProps<DDataBaseListAll>()
 
-const btnLabel = computed<string>(() => isSeeMore.value ? "折叠" : '查看更多');
-const isSeeMore = computed<boolean>(() => pageNum.value > 1 && props.dataList.length === 0)
+const btnLabel = computed<string>(() => props.showMore ? "折叠" : '查看更多');
 
 console.log("传递的props", props.dataList);
 
 const handleSeeMore = () => {
-  if (isSeeMore.value) {
+  if (props.showMore) {
     pageNum.value = 1
   } else {
     pageNum.value++

+ 9 - 9
src/views/Database/components/context-head.vue

@@ -35,15 +35,15 @@ const form = ref<Pick<DTabStore, 'type'> & Pick<DTabStore, 'allStatus'>>({
   allStatus: "1",
 });
 const emit = defineEmits<DEmit>();
-watch(
-  () => route.query,
-  () => {
-    form.value.allStatus = '1'
-  },
-  {
-    immediate: true,
-  }
-);
+//watch(
+//  () => route.query,
+//  () => {
+//    form.value.allStatus = '1'
+//  },
+//  {
+//    immediate: true,
+//  }
+//);
 watch(
   () => form.value.allStatus,
   () => {

+ 12 - 13
src/views/Database/components/context-share.vue

@@ -1,22 +1,19 @@
 <template>
   <div class="share" v-if="type === '5'">
-    <div class="show" @click.stop="useCopyText(props.content!)">复制话术内容</div>
+    <div class="show" @click.stop="useCopyText(props.content!, props.id!)">复制话术内容</div>
     <div class="showNum" v-if="allStatus === 1">已使用:{{ props.pv || 0 }}次</div>
   </div>
   <div class="share" v-else>
     <div class="show" @click.stop="handleDetail(props)">查看{{ controlText }}</div>
-    <div
-      class="show"
-      @click.stop="
-    useWeChatShare({
-     type: props.type!,
-     id: props.id!,
-     spId: serviceProviderId as number,
-     imageUrl: imageLink,
-     isShowToast: true,
-    })
-   "
-    >
+    <div class="show" @click.stop="
+      useWeChatShare({
+        type: props.type!,
+        id: props.id!,
+        spId: serviceProviderId as number,
+        imageUrl: imageLink,
+        isShowToast: true,
+      })
+      ">
       分享
     </div>
   </div>
@@ -59,11 +56,13 @@ const handleDetail = ($event: DArchiveResultData) => {
 .share {
   display: flex;
   align-items: center;
+
   .show {
     margin-left: 24px;
     color: $basicColor;
     font-size: $basicFS;
   }
+
   .showNum {
     margin-left: 24px;
     background: #f5f5f5;

+ 105 - 72
src/views/Database/components/search-head.vue

@@ -3,8 +3,11 @@
     <van-search
       v-model="value"
       placeholder="请输入搜索关键词"
-      @search="emit('handle-search-emit', value)"
-    />
+      @search="emit('handle-search-emit', value)">
+      <template #right-icon>
+        <van-icon name="https://static.caimei365.com/app/mini-database/search.png" />
+      </template>
+    </van-search>
     <van-dropdown-menu active-color="#FF5B00">
       <van-dropdown-item
         active-color="#FF5B00"
@@ -13,7 +16,6 @@
         v-for="(i, o) in menuTypeOptions"
         :key="o"
         v-model="i.changeValue"
-        :options="i.type !== 'Double' ? i.options : []"
         @close="handleDropdownClose"
         @open="handleOpen(o)"
       >
@@ -21,8 +23,8 @@
           <van-search
             v-model="labelKeyParams.v"
             placeholder="请输入搜索关键词"
-            @search="reqLabelKeyList"
-          />
+            @search="reqLabelKeyList">
+          </van-search>
         </template>
         <template v-if="o === 1">
           <van-search
@@ -37,34 +39,55 @@
               <van-cell
                 v-for="(item, index) in i.options"
                 clickable
+                :title="item!.text"
                 :key="index"
-                :title="item.text"
-                @click="toggle(item.value)"
-                :class="checked.indexOf(item.value) > -1 ? 'd-checked' : ''"
+                @click="toggle(item!)"
+                :class="checked.indexOf(item!.value) > -1 ? 'd-checked' : ''"
               >
                 <template #right-icon>
                   <van-checkbox
-                    :name="item.value"
-                    :ref="($event: VNodeRef) => ((checkboxRefs[item.value]) = $event)"
+                    :name="item!.value"
+                    :ref="($event: VNodeRef) => ((checkboxRefs[item!.value]) = $event)"
                   />
                 </template>
               </van-cell>
             </van-cell-group>
           </van-checkbox-group>
         </template>
+        <template v-if="i.type === 'Singular'">
+          <van-radio-group v-model="i.changeValue">
+            <van-cell-group inset>
+              <van-cell
+                v-for="(item, index) in i.options"
+                clickable
+                :key="index"
+                @click="i.changeValue = item.value"
+                :class="i.changeValue === item.value ? 'd-checked' : ''"
+              >
+                <template #title>
+                  <span v-html="item.text" class="custom-title"></span>
+                </template>
+                <template #right-icon>
+                  <van-radio
+                    :name="item!.value"
+                  />
+                </template>
+              </van-cell>
+            </van-cell-group>
+          </van-radio-group>
+        </template>
       </van-dropdown-item>
     </van-dropdown-menu>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onBeforeUpdate, onMounted, VNodeRef } from "vue";
-import type { DMenu, DMenuList, DEmit } from "@/types/views/database.type";
+import { ref, onBeforeUpdate, onMounted, VNodeRef } from "vue";
+import type { DMenu, DEmit } from "@/types/views/database.type";
+import { menuTypeOptions } from "@/types/views/database.type";
 import { getLabelKeyList, getStoreList } from "@/api/context/context";
 import { CheckboxInstance } from "vant";
 import { ILabelKeyRequest, IStoreRequest } from "@/types/api/context.type";
-
-type menuOptions = Array<DMenuList<DMenu>>; // 菜单类型
 const activePadding = ref<string>("20vw 1vw 1vw 1vw"); // vue 样式
 const handleOpen = (val: number) => {
   activePadding.value = val < 2 ? "20vw 1vw 1vw 1vw" : "5vw 1vw 1vw 1vw";
@@ -80,52 +103,29 @@ const labelKeyParams = ref<ILabelKeyRequest>({
   v: "",
 }); // 搜索条件
 const value = ref<string>(""); // 标题搜索
-const checked = ref<Array<number | null>>([]); // 默认选中
+const checked = ref<Array<number | null>>([]); // 默认选中 多选
 const checkboxRefs = ref<Array<CheckboxInstance | VNodeRef>>([]); // 多选默认
 
-const menuTypeOptions = reactive<menuOptions>([
-  {
-    type: "Double",
-    title: "标签",
-    options: [],
-  },
-  {
-    type: "Singular",
-    title: "商品",
-    changeValue: 0,
-    options: [],
-  },
-  {
-    type: "Singular",
-    title: "用户阶段",
-    changeValue: 0,
-    options: [
-      {
-        text: "用户阶段(全部)",
-        value: 0,
-      },
-      {
-        text: "认知阶段",
-        value: 1,
-      },
-      {
-        text: "兴趣阶段",
-        value: 2,
-      },
-      {
-        text: "决策阶段",
-        value: 3,
-      },
-      {
-        text: "购买阶段",
-        value: 4,
-      },
-    ],
-  },
-]);
-
-const toggle = (index: number) => {
-  (checkboxRefs.value[index] as CheckboxInstance).toggle();
+const checkHistoryList = ref<Array<DMenu>>([]);
+const toggle = (index: DMenu) => {
+  (checkboxRefs.value[index.value] as CheckboxInstance).toggle();
+  if (!checkHistoryList.value!.some((e) => e.value === index.value)) {
+    checkHistoryList.value!.push(index);
+  } else {
+    checkHistoryList.value = checkHistoryList.value!.filter(
+      (e) => e.value !== index.value
+    );
+  }
+  menuTypeOptions[0]!.options = [
+    ...checkHistoryList.value,
+    ...menuTypeOptions[0]!.options
+      .map((i) => {
+        if (!checkHistoryList.value!.some((e) => e.value === i.value)) {
+          return i;
+        }
+      })
+      .filter((f) => f),
+  ];
 };
 const emit = defineEmits<DEmit>();
 const handleDropdownClose = (): void => {
@@ -135,22 +135,26 @@ const handleDropdownClose = (): void => {
     stageStatus: menuTypeOptions[2].changeValue!.toString(),
   });
 };
-
 const reqLabelKeyList = async () => {
   const { data } = await getLabelKeyList(labelKeyParams.value);
-  menuTypeOptions[0].options = data!.list!.map((e) => ({
-    text: e.v,
-    value: Number(e.k),
-  }));
+  menuTypeOptions[0]!.options = [
+    ...checkHistoryList.value,
+    ...data!.list!.map((e) => ({
+      text: e.v,
+      value: Number(e.k),
+    })),
+  ];
 };
 const reqStoreList = async () => {
   const { data } = await getStoreList(storeParams.value);
-  menuTypeOptions[1].options = [{ text: '商品(全部)',value: 0 }, ...data!.list!.map((e) => ({
-    text: e.productName,
-    value: e.productId,
-  }))]
+  menuTypeOptions[1]!.options = [
+    { text: "商品(全部)", value: 0 },
+    ...data!.list!.map((e) => ({
+      text: e.productName,
+      value: e.productId,
+    })),
+  ];
 };
-
 onMounted(() => {
   reqLabelKeyList();
   reqStoreList();
@@ -169,23 +173,36 @@ onBeforeUpdate(() => {
 }
 :deep() {
   .van-search {
+    width: 100%;
     height: 38px;
     font-size: 13px;
     padding: 0;
     border: 1px solid #e1e1e1;
+    box-sizing: border-box;
+    border-radius: 1px 1px 1px 1px;
+    .van-field__left-icon {
+      display: none;
+    }
     .van-search__field {
       padding: 0;
     }
     .van-search__content {
       background: #fff;
+      padding: 0 12px;
+      box-sizing: border-box;
     }
-    .van-field__left-icon .van-icon {
+    .van-field__right-icon .van-icon {
       width: 24px;
       height: 24px;
+      .van-icon__image {
+        width: 100%;
+        height: 100%;
+      }
     }
   }
   .van-cell-group--inset {
     margin: 0;
+    transition: all 0.3s;
   }
   .van-dropdown-menu {
     height: 50px;
@@ -202,13 +219,18 @@ onBeforeUpdate(() => {
     position: relative;
   }
   .van-cell {
-    padding: 7.5px;
+    padding: 7.5px 18px;
+    transition: all 0.3s;
     .van-cell__title {
       color: rgb(37, 1, 1);
       font-size: 13px;
+      .custom-title span {
+        color: #999999;
+      }
     }
   }
   .van-checkbox__icon--checked .van-icon,
+  .van-radio__icon .van-icon,
   .van-checkbox__icon .van-icon {
     background: none;
     border: none;
@@ -223,13 +245,17 @@ onBeforeUpdate(() => {
       color: $basicColor !important;
     }
   }
-
+  .van-dropdown-menu__title:after {
+    border: 4px solid;
+    border-color: transparent transparent #B1B1B1 #B1B1B1;
+    transform: translateY(-16%) rotate(-45deg);
+  }
   .van-dropdown-menu__title--active::before {
     content: "";
     position: absolute;
     width: 30px;
     height: 2px;
-    background: $basicColor;
+    background: $basicColor !important;
     bottom: -4px;
     left: 50%;
     transform: translateX(-50%);
@@ -255,6 +281,10 @@ onBeforeUpdate(() => {
       width: 80%;
     }
   }
+  .van-dropdown-menu__title--active::after {
+    border-color: transparent transparent $basicColor $basicColor !important;
+    transform: translateY(-16%) rotate(135deg);
+  }
 }
 .d-checked {
   :deep() {
@@ -262,6 +292,9 @@ onBeforeUpdate(() => {
     .van-cell__title {
       color: $basicColor;
     }
+    .van-radio__icon--checked .van-icon {
+      color: $basicColor;
+    }
   }
 }
 .activeMenu {

+ 3 - 3
src/views/Database/data-all/index.vue

@@ -3,7 +3,7 @@
     <context-contain
       :type="data.type"
       :data-list="data.dataList"
-      :show-more="showSeeMore"
+      :show-more="data.showMore"
       v-if="data.dataList.length > 0 && data.type !== '0' && data.type !== '5'"
       @handle-see-more="handleSeeMore"
     >
@@ -80,7 +80,6 @@ const reqParams = computed<IArchiveRequest>(
 const isAddStatus = ref<boolean>(false);
 const isEmpty = ref<boolean>(false);
 const isShowType = ref<boolean>(false);
-const showSeeMore = ref<boolean>(true);
 const formParams = ref({ allStatus: "1" });
 const reqArchiveList = async (res?: DetailParams) => {
   if (!res) {
@@ -91,6 +90,7 @@ const reqArchiveList = async (res?: DetailParams) => {
     }));
     dataList.value = tabList.map((e) => ({
       type: e.type,
+      showMore: false,
       dataList: DcreptoList!.filter((i) => i.type === e.type),
     }));
     isEmpty.value = data?.length === 0;
@@ -109,7 +109,7 @@ const reqArchiveList = async (res?: DetailParams) => {
     ];
     isEmpty.value =
       dataList.value![res.type]!.dataList.length === 0 && reqParams.value.type !== "";
-    showSeeMore.value = data?.length! < 5;
+    dataList.value![res.type]!.showMore = res.pageNum! > 1 && data?.length! < 5;
   }
 };
 watch(

+ 2 - 2
src/views/Database/detail.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="detail">
     <div class="other" v-if="type === '5'">
-      {{ '个人话术' }}<span>已使用:{{ form?.pv || 0 }}次</span>
+      {{ form?.allStatus === 2 ? '个人话术' : '企业话术' }}<span v-if="form?.allStatus === 1">已使用:{{ form?.pv || 0 }}次</span>
     </div>
     <div class="time">{{ form?.addTime }}</div>
     <div class="title">{{ form?.title }}</div>
@@ -51,7 +51,7 @@
         v-if="type === '3'"
       />
       <data-button
-        @handle-emit="useCopyText(form?.content!)"
+        @handle-emit="useCopyText(form?.content!, form?.id as string)"
         backgroundColor="#FFF"
         color="#FF5B00"
         label="复制文本"

+ 4 - 2
src/views/Login/index.vue

@@ -30,6 +30,7 @@ import { ref, computed } from "vue";
 import { useUserInfoState } from "@/store/user/user";
 import { useRouter } from "vue-router";
 import { ILogin } from "@/types/api/user.type";
+import { showLoadingToast } from 'vant';
 
 const router = useRouter();
 
@@ -46,12 +47,13 @@ const disabled = computed<boolean>(() => (!form.value.mobileOrEmail || !form.val
 
 const onSubmit = async () => {
   if (!disabled.value) {
-    const { data, code } = await login(form.value);
+    const { data, code, msg } = await login(form.value);
     console.log(data);
     if (code === 0) {
+      showLoadingToast(msg!)
       router.replace('/database/index?t=0')
     } else {
-      console.log('登录错误')
+      showLoadingToast(msg!)
     }
   }
 };

+ 51 - 16
src/views/Preview/index.vue

@@ -1,7 +1,15 @@
 <template>
-  <video-preview v-if="params.type === '2' && fileUrl" :url="fileUrl" :is-permi="isPermi"/>
-  <pdf-preview v-if="params.type === '3' && fileUrl" :url="fileUrl" :is-permi="isPermi"/>
-  <image-preview v-if="params.type === '1' && form?.waters" :urls="form?.waters" :is-permi="isPermi"/>
+  <video-preview
+    v-if="params.type === '2' && fileUrl"
+    :url="fileUrl"
+    :is-permi="isPermi"
+  />
+  <pdf-preview v-if="params.type === '3' && fileUrl" :url="fileUrl" :is-permi="isPermi" />
+  <image-preview
+    v-if="params.type === '1' && form?.waters"
+    :urls="form?.waters"
+    :is-permi="isPermi"
+  />
   <permi-mode v-if="!query.isSp" />
   <!--<iframe frameborder="0" src="http://localhost:8009/login.html" />-->
   <!--<div class="hidden">
@@ -15,12 +23,14 @@
 import { usePermission } from "@/Hooks/usePermission/usePermission";
 import { previewData } from "@/api/context/context";
 import useStatisticalTime from "@/Hooks/useStatisticalTime";
-import { onMounted, computed, onUnmounted, ref } from "vue";
+import { onMounted, computed, onUnmounted, ref, watch } from 'vue';
 import { useRoute } from "vue-router";
 import { ChangeTabEmit } from "@/types/views/database.type";
-import useWeChatShare, { shareParams } from "@/Hooks/useWeChatShare";
+import useWeChatShare, { shareOptions, shareParams } from "@/Hooks/useWeChatShare";
 import { IPreviewForm } from "@/types/api/context.type";
 import { myDecrypt } from "@/util/authStorage";
+import useStopWindowContext from "@/Hooks/useStopWindowContext";
+import createWebShareCard from "@/Hooks/useCreateWebShareCard";
 const { query } = useRoute();
 
 const form = ref<IPreviewForm>({
@@ -28,6 +38,7 @@ const form = ref<IPreviewForm>({
   permission: 0,
   productId: "0",
   fileArchiveList: [],
+  image: "",
 });
 
 //if (!window.localStorage.getItem("pageHide")) {
@@ -42,8 +53,22 @@ const form = ref<IPreviewForm>({
 //const pageHide = window.localStorage.getItem("pageHide");
 //const visibility = window.localStorage.getItem("visibility");
 //const onbeforeLoad = window.localStorage.getItem("onbeforeLoad");
-
 const fileUrl = ref<string>();
+const { isPermi, PermiMode } = usePermission(form.value?.permission! as number); // 权限hook
+const params = computed<shareParams & { url: string }>(
+  () =>
+    (({
+      type: query?.t as ChangeTabEmit,
+      userId: query?.uid as string,
+      id: query?.id as string,
+      spId: query?.spId as string,
+      imageUrl: form.value?.image,
+      url: query?.url as string,
+    } as unknown) as shareParams & { url: string })
+);
+watch(() => params.value.url, () => {
+  fileUrl.value = params.value.url
+})
 const getPreviewData = async () => {
   const { data } = await previewData({
     userId: (query.uid as string) || "0",
@@ -58,13 +83,6 @@ const getPreviewData = async () => {
   fileUrl.value = form.value.waters[0]?.split("?")[0];
   console.log(form.value.waters);
 };
-const { isPermi, PermiMode } = usePermission(form.value?.permission! as number); // 权限hook
-const params = computed(() => ({
-  type: query.t as ChangeTabEmit,
-  userId: query.uid as string,
-  id: query.id as string,
-  spId: query.spId as string,
-}));
 const statistical = useStatisticalTime((time) => {
   const t = Math.floor(time / 1000);
   console.log("时长为:", t, Math.floor(time / 1000));
@@ -75,7 +93,7 @@ const statistical = useStatisticalTime((time) => {
     accessClient: "0",
     pagePath: location.href,
     accessDuration: t * 1000,
-    pageType: params.value.type === '1' ? '70' : params.value.type === '2' ? '71' : '69',
+    pageType: params.value.type === "1" ? "70" : params.value.type === "2" ? "71" : "69",
     pageLabel: "内容库预览",
     userId: params.value.userId || "0",
     productId: form.value?.productId || "0",
@@ -105,17 +123,29 @@ const statistical = useStatisticalTime((time) => {
       console.log("时间推送记录成功");
     });
 });
+useStopWindowContext(params.value.userId!);
 onUnmounted(() => {
   statistical();
 });
 
 onMounted(() => {
-  getPreviewData();
-  useWeChatShare((params.value! as unknown) as shareParams);
+  const obj = shareOptions.filter(e => e.type === params.value.type)[0]
+  if (!params.value.url) {
+    getPreviewData();
+  }
+  useWeChatShare(params.value);
+  createWebShareCard({
+    title: obj.text,
+    description: obj.text,
+    image: params.value.imageUrl!,
+  });
 });
 </script>
 
 <style scoped lang="scss">
+body {
+  user-select: none !important;
+}
 .hidden {
   width: 100vw;
   height: 100vh;
@@ -124,4 +154,9 @@ onMounted(() => {
   justify-content: center;
   flex-direction: column;
 }
+@media print {
+  .no-print {
+    display: none !important;
+  }
+}
 </style>