xiebaomin 1 éve
szülő
commit
4eb730eba4
42 módosított fájl, 1732 hozzáadás és 281 törlés
  1. 3 1
      .env.development
  2. 10 0
      components.d.ts
  3. 38 13
      src/Hooks/usePermission/permiMode.tsx
  4. 6 6
      src/Hooks/usePermission/usePermission.ts
  5. 9 0
      src/Hooks/useSeeMore.ts
  6. 50 0
      src/Hooks/useStatisticalTime.ts
  7. 48 0
      src/Hooks/useWeChatShare.ts
  8. 23 0
      src/api/context/context.ts
  9. 2 2
      src/api/user/login.ts
  10. 48 0
      src/components/data-button/data-button.vue
  11. 3 4
      src/router/index.ts
  12. 1 0
      src/router/route.d.ts
  13. 51 25
      src/router/route.ts
  14. 0 16
      src/store/counter/counter.ts
  15. 22 0
      src/store/tab/tab.ts
  16. 10 0
      src/store/tab/tab.type.ts
  17. 2 2
      src/store/user/user.ts
  18. 15 1
      src/styles/variables.scss
  19. 70 0
      src/types/api/context.type.ts
  20. 18 0
      src/types/api/index.ts
  21. 2 1
      src/types/api/user.type.ts
  22. 18 0
      src/types/components-type/data-button.type.ts
  23. 89 0
      src/types/views/database.type.ts
  24. 19 9
      src/util/http.ts
  25. 89 0
      src/views/Database/components/context-contain.vue
  26. 83 0
      src/views/Database/components/context-head.vue
  27. 54 0
      src/views/Database/components/context-share.vue
  28. 43 0
      src/views/Database/components/file-content.vue
  29. 16 0
      src/views/Database/components/high-light-text.vue
  30. 67 0
      src/views/Database/components/scroll-tap-btn.vue
  31. 250 0
      src/views/Database/components/search-head.vue
  32. 53 0
      src/views/Database/components/text-file-content.vue
  33. 109 0
      src/views/Database/components/video-img-content.vue
  34. 84 0
      src/views/Database/data-all/index.vue
  35. 179 0
      src/views/Database/detail.vue
  36. 0 10
      src/views/Database/index.type.ts
  37. 63 79
      src/views/Database/index.vue
  38. 0 13
      src/views/Home/index.vue
  39. 79 51
      src/views/Login/index.vue
  40. 0 23
      src/views/Preview/components/layout.vue
  41. 0 4
      src/views/Preview/index.type.ts
  42. 6 21
      src/views/Preview/index.vue

+ 3 - 1
.env.development

@@ -2,4 +2,6 @@ VITE_ENV = 'development'
 
 VITE_BASE_URL = 'https://core-b.caimei365.com'
 
-VITE_BASE_OSS = 'https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/'
+VITE_BASE_OSS = 'https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/'
+
+VITE_IMAGE_URL = 'https://static.caimei365.com/'

+ 10 - 0
components.d.ts

@@ -7,6 +7,7 @@ export {}
 
 declare module 'vue' {
   export interface GlobalComponents {
+    DataButton: typeof import('./src/components/data-button/data-button.vue')['default']
     ImagePreview: typeof import('./src/components/image-preview/image-preview.vue')['default']
     PdfPreview: typeof import('./src/components/pdf-preview/pdf-preview.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
@@ -14,8 +15,17 @@ declare module 'vue' {
     VanButton: typeof import('vant/es')['Button']
     VanCell: typeof import('vant/es')['Cell']
     VanCellGroup: typeof import('vant/es')['CellGroup']
+    VanCheckbox: typeof import('vant/es')['Checkbox']
+    VanCheckboxGroup: typeof import('vant/es')['CheckboxGroup']
+    VanDropdownItem: typeof import('vant/es')['DropdownItem']
+    VanDropdownMenu: typeof import('vant/es')['DropdownMenu']
     VanField: typeof import('vant/es')['Field']
     VanForm: typeof import('vant/es')['Form']
+    VanHighlight: typeof import('vant/es')['Highlight']
+    VanImage: typeof import('vant/es')['Image']
+    VanSearch: typeof import('vant/es')['Search']
+    VanTab: typeof import('vant/es')['Tab']
+    VanTabs: typeof import('vant/es')['Tabs']
     VideoPreview: typeof import('./src/components/video-preview/video-preview.vue')['default']
   }
 }

+ 38 - 13
src/Hooks/usePermission/permiMode.tsx

@@ -1,10 +1,10 @@
-import { ComponentOptions, defineComponent } from 'vue'
+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';
 
-const MyComponent = (prop: IPermiObj | Boolean, permi: number): ComponentOptions =>
+const MyComponent = (prop: IPermiObj | Boolean): ComponentOptions =>
 	defineComponent({
 		name: 'MyComponent',
 		components: {
@@ -15,40 +15,65 @@ const MyComponent = (prop: IPermiObj | Boolean, permi: number): ComponentOptions
 			const FixDivMode = css`
 				width: 100vw;
 				height: 100vh;
-				background-color: rgba(255, 255, 255, 0.5);
 				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%);
 			`
 			const FixTips = css`
 				font-size: 14px;
-				position: absolute;
-				bottom: 200px;
 				text-align: center;
 				width: 100%;
-				color: red;
+				color: #666666;
+				height: calc(100vh - 185px);
+				background: #fff;
+				padding-top: 138px;
+				box-sizing: border-box;
 			`
 			const FixBtn = css`
-				font-size: 16px;
-				margin-top: 10px;
-				width: 160px;
-				height: 50px;
+				font-size: 13px;
+				margin-top: 15px;
+				width: 315px;
+				height: 42px;
 				white-space: nowrap;
+				background-color: #FF5B00;
+				color: #FFF;
 			`
 			const handleClick = () => {
-				console.log(permi)
+				//window.localStorage.setItem('permission', '0')
+				window.open('https://www.caimei365.com/')
+			}
+			const pageLocation = ref<number>(0)
+			const stop = () => {
+				pageLocation.value = window.scrollY
+				document.body.style.position = 'fixed'
+				document.body.style.top = '-' + pageLocation.value + 'px'
+			}
+			const move = () => {
+				document.body.style.position = 'static';
+    		window.scrollTo(0, pageLocation.value);
 			}
 			return {
 				FixTips,
 				FixDivMode,
 				FixBtn,
+				FixUpperLevels,
 				handleClick,
-				obj
+				obj,
+				stop,
+				move
 			}
 		},
 		render() {
-			console.log(prop)
+			prop ? this.stop() : this.move()
 			return prop && <div class={this.FixDivMode}>
+				<div class={this.FixUpperLevels}></div>
 				<div class={this.FixTips}>
 					<div>
 						{this.obj.text}

+ 6 - 6
src/Hooks/usePermission/usePermission.ts

@@ -4,17 +4,17 @@ import MyComponent from './permiMode.tsx'
 //用户权限  0可查看,1未登录,2需升级会员机构,3需升级医美会员机构,4需要抵扣采美豆,5无权限查看
 const permissionText: IPermi = [
 	false,
-	{ text: '请登录后查看!', btnText: '去登录', redirect: '/pages/login/login' },
-	{ text: '请升级成为会员机构后方可查看!', btnText: '去升级', redirect: '/pages/login/apply' },
-	{ text: '请升级成为医美会员机构后方可查看!', btnText: '去升级', redirect: '/pages/login/apply' },
-	{ text: '需抵扣100采美豆方可查看!', btnText: '去查看', redirect: '' },
+	{ text: '登录后查看完整内容', btnText: '去登录', redirect: '/pages/login/login' },
+	{ text: '医美资质机构可查看完整内容', btnText: '去升级', redirect: '/pages/login/apply' },
+	{ text: '医美资质机构可查看完整内容', btnText: '去升级', redirect: '/pages/login/apply' },
+	{ text: '医美资质机构可查看完整内容', btnText: '去查看', redirect: '' },
 	{ text: '无权限查看!', btnText: '确认' },
 ]
 
 export const usePermission = (): UsePermission => {
-	const permi = (): number => window.localStorage.getItem('permission') !== null ? Number(window.localStorage.getItem('permission')) : 1
+	const permi = (): number => window.sessionStorage.getItem('permission') !== null ? Number(window.sessionStorage.getItem('permission')) : 1
 	const isPermi = (): Boolean | IPermiObj => permissionText[permi()]
-	const cE = MyComponent(isPermi(), permi())
+	const cE = MyComponent(isPermi())
 	return {
 		isPermi: !isPermi(),
 		PermiMode: isPermi() && cE,

+ 9 - 0
src/Hooks/useSeeMore.ts

@@ -0,0 +1,9 @@
+let index = 0
+
+const sliceArr = <T>(arr: Array<T>, sliceIndex: number): Array<T> => {
+	const i = sliceIndex += index
+	const copy = JSON.parse(JSON.stringify(arr))
+	return copy.slice(0, i)
+}
+
+export default sliceArr;

+ 50 - 0
src/Hooks/useStatisticalTime.ts

@@ -0,0 +1,50 @@
+/**
+ * 移动端时间统计 hook
+ */
+
+import { onMounted, onUnmounted } from "vue"
+
+
+const useStatisticalTime = (callback: (timing: number) => void) => {
+	const startTiming = () => {
+		if (localStorage.getItem('timing')) {
+			localStorage.removeItem('timing');
+		}
+		const startTime = new Date().valueOf().toString()
+		console.log('开始统计在线时长', startTime)
+		localStorage.setItem('timing', startTime)
+	}
+
+	const endTiming = async () => {
+		const startTime = Number(localStorage.getItem('timing'))
+		const endTime = new Date().valueOf()
+		if (startTime) {
+			console.log('统计时间结束', startTime, endTime)
+			const timing = endTime - startTime
+			await callback(timing)
+			localStorage.removeItem('startTime')
+		}
+	}
+
+	onMounted(() => {
+		startTiming()
+		window.addEventListener('pagehide', async () => {
+			console.log('页面关闭')
+			await endTiming()
+		})
+	})
+	
+	onUnmounted(() => {
+		window.addEventListener('pagehide', async () => {
+			console.log('页面关闭')
+			await endTiming()
+		})
+		localStorage.removeItem('timing')
+	})
+
+	return () => {
+		window.removeEventListener('pagehide', () => {})
+	}
+}
+
+export default useStatisticalTime

+ 48 - 0
src/Hooks/useWeChatShare.ts

@@ -0,0 +1,48 @@
+import { DFindParams, DScrollTab, ChangeTabEmit } from '@/types/views/database.type';
+
+type shareOptions = {
+	type: ChangeTabEmit,
+	imageUrl: string
+	text: `您的好友给你分享了${DFindParams<DScrollTab, 'text'>}链接`
+}
+
+const shareOptions: shareOptions[] = [
+	{
+		type: '1',
+		imageUrl: '',
+		text: '您的好友给你分享了文件链接'
+	},
+	{
+		type: '2',
+		imageUrl: '',
+		text: '您的好友给你分享了视频链接'
+	},
+	{
+		type: '3',
+		imageUrl: '',
+		text: '您的好友给你分享了图片链接'
+	},
+	{
+		type: '4',
+		imageUrl: '',
+		text: '您的好友给你分享了文章链接'
+	},
+	{
+		type: '5',
+		imageUrl: '',
+		text: '您的好友给你分享了百科链接'
+	},
+	{
+		type: '6',
+		imageUrl: '',
+		text: '您的好友给你分享了文本链接'
+	}
+]
+
+const useWeChatShare = () => {
+	
+
+	return {}
+}
+
+export default useWeChatShare

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

@@ -0,0 +1,23 @@
+import type {
+	ILabelKeyRequest,
+	DLabelKeyResultData,
+	ContextRequest,
+	DArchiveResultData,
+	IArchiveListRequest,
+	DStoreResultData,
+	IStoreRequest,
+	IArchiveForm,
+} from '@/types/api/context.type'
+import { requestGET } from '@/types/api/index'
+
+export const getLabelKeyList = (data: ILabelKeyRequest) =>
+	requestGET<ContextRequest, DLabelKeyResultData>('/commodity/product/archive/findKeyWordList', data)
+
+export const getArchiveList = (data: IArchiveListRequest) =>
+	requestGET<ContextRequest, DArchiveResultData[]>('/commodity/product/archive/list', data)
+
+export const getStoreList = (data: IStoreRequest) =>
+	requestGET<ContextRequest, DStoreResultData>('/commodity/product/archive/findProductList', data)
+
+export const getArchiveFormDetails = (data: IArchiveForm) =>
+	requestGET<ContextRequest, DArchiveResultData>('/commodity/product/archive/from', data)

+ 2 - 2
src/api/user/login.ts

@@ -1,6 +1,6 @@
-import type { ILogin, ILoginRequestData, IUserInfo, LoginRequest } from './index.type'
+import type { ILogin, ILoginRequestData, IUserInfo, LoginRequest } from '@/types/api/user.type'
 import { requestPOST, requestGET } from '@/types/api/index';
 
-export const login = (data: ILogin) => requestPOST<LoginRequest, ILoginRequestData>('/user/login/password', data)
+export const login = (data: ILogin) => requestPOST<LoginRequest, ILoginRequestData>('/user/login/seller', data)
 
 export const getUserInfo = (params: Pick<IUserInfo, 'userId'>) => requestGET<LoginRequest, ILoginRequestData>('/user/login/userInfo', params)

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

@@ -0,0 +1,48 @@
+<template>
+  <van-button
+    :disabled="disabled"
+    :class="disabled && 'disabled'"
+    :style="{ backgroundColor, width, color, height }"
+    @click="handleClick"
+    :icon="icon"
+    :size="size"
+    :icon-position="iconPosition"
+  >
+    {{ label }}
+  </van-button>
+</template>
+
+<script setup lang="ts">
+import type { Dbutton, DEmit } from "@/types/components-type/data-button.type";
+
+withDefaults(defineProps<Dbutton>(), {
+  label: "按钮",
+  disabled: false,
+  backgroundColor: "#FF5B00",
+  width: '100%',
+  color: '#fff',
+  size: "normal",
+  icon: "",
+  iconPosition: "right"
+});
+
+const emit = defineEmits<DEmit>()
+
+const handleClick = (): void => {
+  emit('handleEmit')
+}
+
+</script>
+
+<style scoped lang="scss">
+.disabled {
+  background-color: #e2e2e2 !important;
+  color: #ffffff;
+}
+:deep() {
+  .van-button:before {
+		background: none;
+		border: none;
+	}
+}
+</style>

+ 3 - 4
src/router/index.ts

@@ -13,7 +13,7 @@ NProgress.configure({
   showSpinner: false
 })
 
-const whiteList: any = []
+const whiteList: any = ['/database/index', '/login', '/database/other', '/database/detail']
 
 router.beforeEach((to, _, next) => {
 	console.log(to)
@@ -26,11 +26,10 @@ router.beforeEach((to, _, next) => {
 	} else {
     // 没有token
     if (whiteList.indexOf(to.path) !== -1) {
-      next()
+			next()
       // 在免登录白名单,直接进入
     } else {
-      next() // 否则全部重定向到登录页
-      NProgress.done()
+      next('/') // 否则全部重定向到登录页
     }
   }
 })

+ 1 - 0
src/router/route.d.ts

@@ -8,5 +8,6 @@ declare module 'vue-router' {
 		isIframe?: boolean;
 		roles?: string[];
 		icon?: string;
+		id?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7'
 	}
 }

+ 51 - 25
src/router/route.ts

@@ -1,29 +1,29 @@
 import { RouteRecordRaw } from 'vue-router'
 
 
-export const dynamicRoutes: Array<RouteRecordRaw> = [
-	{
-		path: '/',
-		name: 'dashboard',
-		component: () => import('@/Layout/index.vue'),
-		redirect: '/home',
-		meta: {
-			name: 'dashboard'
-		},
-		children: [
-			{
-				path: 'home',
-				name: 'home',
-				component: () => import('@/views/Home/index.vue'),
-				meta: {
-					title: 'message.router.home',
-					roles: ['admin'],
-					icon: 'iconfont icon-shouye'
-				}
-			}
-		]
-	}
-]
+//export const dynamicRoutes: Array<RouteRecordRaw> = [
+//	{
+//		path: '/',
+//		name: 'dashboard',
+//		component: () => import('@/Layout/index.vue'),
+//		redirect: '/home',
+//		meta: {
+//			name: 'dashboard'
+//		},
+//		children: [
+//			{
+//				path: 'home',
+//				name: 'home',
+//				component: () => import('@/views/Home/index.vue'),
+//				meta: {
+//					title: 'message.router.home',
+//					roles: ['admin'],
+//					icon: 'iconfont icon-shouye'
+//				}
+//			}
+//		]
+//	}
+//]
 
 export const notFoundPower: Array<RouteRecordRaw> = [
 	{
@@ -64,12 +64,38 @@ export const staticRouter: Array<RouteRecordRaw> = [
 		meta: {
 			title: '文件预览'
 		}
-	}, {
+	}, 
+	{
 		path: '/database',
 		name: 'database',
+		redirect: '/database/index',
 		component: () => import('@/views/Database/index.vue'),
+		children: [
+			{
+				path: 'index',
+				name: 'All',
+				component: () => import('@/views/Database/data-all/index.vue'),
+				meta: {
+					title: '文件资料',
+				}
+			},
+			//{
+			//	path: 'other',
+			//	name: 'Other',
+			//	component: () => import('@/views/Database/data-other/index.vue'),
+			//	meta: {
+			//		title: '文件资料',
+			//		icon: ''
+			//	}
+			//}
+		]
+	},
+	{
+		path: '/database/detail',
+		name: 'Detail',
+		component: () => import('@/views/Database/detail.vue'),
 		meta: {
-			title: '文件资料'
+			title: '文件详情',
 		}
 	}
 ]

+ 0 - 16
src/store/counter/counter.ts

@@ -1,16 +0,0 @@
-import { defineStore } from "pinia";
-
-export const useCounterStore = defineStore('counter', {
-	state: (): { counter: number } => ({
-		counter: 0
-	}),
-	actions: {
-		async addCounter (): Promise<number> {
-			return new Promise((resolve) => {
-				this.counter++
-				resolve(this.counter)
-			})
-		}
-	},
-	persist: true
-})

+ 22 - 0
src/store/tab/tab.ts

@@ -0,0 +1,22 @@
+import { defineStore } from "pinia";
+import { DTabStore } from "./tab.type";
+
+export const useTabStore = defineStore('myTabStore', {
+	state: (): DTabStore => ({
+		type: "0",
+		stageStatus: '',
+		productId: 0,
+		labelIds: '',
+		searchValue: ''
+	}),
+	actions: {
+		updatedTabStore(step: Partial<DTabStore>) {
+			this.stageStatus = step?.stageStatus
+			this.type = step?.type!
+			this.productId = step?.productId
+			this.labelIds = step?.labelIds
+			this.searchValue = step?.searchValue!
+		}
+	},
+	persist: true
+})

+ 10 - 0
src/store/tab/tab.type.ts

@@ -0,0 +1,10 @@
+import { IArchiveRequest } from "@/types/api/context.type"
+import { DFindParams, DScrollTab } from "@/types/views/database.type"
+
+export type DTabStore = {
+	type: DFindParams<DScrollTab, 'type'>
+	labelIds: DFindParams<IArchiveRequest, 'labelIds'>
+	stageStatus: DFindParams<IArchiveRequest, 'stageStatus'>
+	productId: DFindParams<IArchiveRequest, 'productId'>
+	searchValue: string
+}

+ 2 - 2
src/store/user/user.ts

@@ -2,7 +2,7 @@ import { defineStore } from "pinia";
 import { getStorage } from "@/util/authStorage"
 import type { UserInfo, UserInfoState } from './user.type';
 import { login } from '@/api/user/login';
-import { ILogin, ILoginRequestData } from '@/api/user/index.type';
+import { ILogin, ILoginRequestData } from '@/types/api/user.type';
 import { IResultData } from '@/types/api/index';
 
 
@@ -18,7 +18,7 @@ export const useUserInfoState = defineStore('userInfo', {
 			}
 		},
 		login(data: ILogin): Promise<IResultData<ILoginRequestData>> {
-			return new Promise<IResultData<ILoginRequestData>>(async (resolve, reject) => {
+			return new Promise(async (resolve, reject) => {
 				try {
 					const res = await login(data)
 					//this.permission = res.data!.permission || 1

+ 15 - 1
src/styles/variables.scss

@@ -22,4 +22,18 @@
 	display: flex;
 	justify-content: space-between;
 	align-items: center;
-}
+}
+
+@mixin display-column-end {
+	display: flex;
+	justify-content: flex-end;
+	align-items: center;
+	flex-direction: column;
+}
+
+$bgColor: #F5F5F5;
+$basicColor-content: #333333;
+$basicColor: #FF5B00;
+$basicFS: 13px;
+$basicFS-foot: 12px;
+$basicColor-foot: #999;

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

@@ -0,0 +1,70 @@
+import { ChangeTabEmit } from "../views/database.type";
+import { DResultListData, IGlobalListRequest } from "./index";
+
+
+export type ILabelKeyResultData = { // 标签返回
+	v: string;
+	k: string;
+}
+
+export interface DArchiveResultData extends IArchiveRequest { // 列表返回
+	addTime?: string
+	content?: string
+	id?: string
+	image?: string
+	productType?: string
+	shopName?: string
+	waters?: Array<string>
+	productArchiveId?: number
+	productClassify?: number
+	keywords?: string
+	pv?: string
+}
+
+export type IStoreResultData = { // 商品返回类型
+	image: string;
+	id?: number
+	productId: number
+	productName: string
+	shopName: string
+} 
+
+export type DLabelKeyResultData = DResultListData<ILabelKeyResultData> 
+
+export type DStoreResultData = DResultListData<IStoreResultData>
+
+export interface ILabelKeyRequest extends IGlobalListRequest { // 参数
+	v: string;
+}
+
+export interface IArchiveRequest { // 参数
+	title?: string
+	userId?: string
+	type?: ChangeTabEmit | null
+	productId?: number | null
+	stageStatus?: string | null
+	allStatus?: string | null
+	labelId?: string
+	labelIds?: string
+	spId?: string
+}
+
+export type IArchiveListRequest = IArchiveRequest & Partial<IGlobalListRequest>
+
+export interface IStoreRequest extends IGlobalListRequest {
+	productName: string,
+	shopName?: string
+	productId?: number
+}
+
+export type IArchiveForm = {
+	id: string
+	userId: string
+}
+
+export interface ContextRequest {
+	'/commodity/product/archive/findKeyWordList': ILabelKeyRequest
+	'/commodity/product/archive/list': IArchiveListRequest
+	'/commodity/product/archive/findProductList': IStoreRequest
+	'/commodity/product/archive/from': IArchiveForm
+}

+ 18 - 0
src/types/api/index.ts

@@ -5,10 +5,28 @@ export interface IResult {
 	code: number;
 }
 
+export type IGlobalListRequest = {
+	pageSize: number;
+	pageNum: number;
+}
+
 export interface IResultData<T = any> extends IResult {
 	data?: T
 }
 
+export interface DResultListData<T = any> {
+	firstPage: number
+	list?: T[] // 数据
+	data?: T[] // 数据
+	hasNextPage: boolean // 是否有下一页
+	hasPreviousPage: boolean // 是否有上一页
+	isFirstPage: boolean // 是否是第一页
+	isLastPage: boolean // 是否是最后一页
+	lastPage: number // 最后一页的页数
+	size: number // 请求每页的数据条数
+	total: number // 总数
+}
+
 export enum RequestEnums {
 	TIME_OUT = 10000,
 	SUCCESS = 200,

+ 2 - 1
src/api/user/index.type.ts → src/types/api/user.type.ts

@@ -1,6 +1,7 @@
 export type ILogin = {
 	mobileOrEmail: string;
 	password: string;
+	isUnion: 1
 }
 
 export type IUserInfo = {
@@ -13,6 +14,6 @@ export type ILoginRequestData = {
 }
 
 export interface LoginRequest {
-	'/user/login/password': ILogin
+	'/user/login/seller': ILogin
 	'/user/login/userInfo': Pick<IUserInfo, 'userId'>
 }

+ 18 - 0
src/types/components-type/data-button.type.ts

@@ -0,0 +1,18 @@
+export interface Dbutton {
+	label?: string
+	disabled?: boolean
+	color?: string
+	fontSize?: number
+	backgroundColor?: string
+	width?: string
+	height?: string
+	nativeType?: string & 'submit'
+	type?: 'primary' | 'success' | 'warning' | 'danger'
+	size?: 'mini' | 'small' | 'large' | 'normal'
+	icon?: 'plus' | string
+	iconPosition?: 'left' | 'right'
+}
+
+export type DEmit = {
+	(e: 'handleEmit'): void
+}

+ 89 - 0
src/types/views/database.type.ts

@@ -0,0 +1,89 @@
+import { DArchiveResultData, IArchiveRequest } from "../api/context.type";
+
+export type DMenu = {
+	text: string;
+	value: number;
+}
+
+export interface DMenuList<T> {
+	type: 'Double' | 'Singular'
+	changeValue?: number
+	options: Array<T>
+	title: string
+}
+
+export type ChangeEmitParams = {
+	labelIds: DFindParams<IArchiveRequest, 'labelIds'>
+	stageStatus: DFindParams<IArchiveRequest, 'stageStatus'>
+	productId: DFindParams<IArchiveRequest, 'productId'>
+}
+
+export type SearchEmitParams = string
+
+export type ChangeTabEmit = DFindParams<DScrollTab, 'type'>
+
+export type DetailParams = {
+  id?: string,
+  type: ChangeTabEmit
+  pageNum?: number
+}
+
+export type DScrollTab = {
+	type: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7'; // tab标签 
+	text: '全部' | '图片' | '视频' | '文件' | '文章' | '百科' | '文本' | '话术';
+}
+
+export const tabList: Array<DScrollTab> = [
+  {
+    type: '0',
+    text: "全部",
+  },
+  {
+    type: '1',
+    text: "图片",
+  },
+  {
+    type: '2',
+    text: "视频",
+  },
+  {
+    type: '3',
+    text: "文件",
+  },
+  {
+    type: '4',
+    text: "文本",
+  },
+  {
+    type: '5',
+    text: "话术",
+  },
+  {
+    type: '6',
+    text: "文章",
+  },
+  {
+    type: '7',
+    text: "百科",
+  },
+]
+
+export interface DEmit {
+	(e: 'handle-change-emit', n: ChangeEmitParams): void
+	(e: 'handle-search-emit', n: NonNullable<DFindParams<IArchiveRequest, 'title'>>): void
+	(e: 'handle-tab-emit', n: DScrollTab): void
+  (e: 'handle-see-more', n: DetailParams): void
+}
+
+export interface DDataBaseListAll {
+  type: ChangeTabEmit
+  dataList: DArchiveResultData[]
+}
+
+export type NonNullable<T> = T extends null | undefined ? never : T;
+
+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>>

+ 19 - 9
src/util/http.ts

@@ -5,11 +5,15 @@ import axios, {
 	AxiosResponse,
 	InternalAxiosRequestConfig
 } from "axios";
-import { showLoadingToast, showSuccessToast, showFailToast } from 'vant'
+import { showLoadingToast, showFailToast } from 'vant'
 import type { IResultData } from '@/types/api/index'
-import { RequestEnums } from '@/types/api/index';
 import { getStorage } from './authStorage';
 
+enum RequestEnums {
+	TIME_OUT = 10000,
+	SUCCESS = 200,
+	CODE = 0
+}
 
 const baseConfig = {
 	baseURL: import.meta.env.VITE_BASE_URL,
@@ -17,8 +21,12 @@ const baseConfig = {
 	withCredentials: true
 }
 
-class RequestHttp {
+interface IRequestClass {
 	service: AxiosInstance
+}
+
+class RequestHttp implements IRequestClass {
+	service: AxiosInstance;
 
 	constructor(config: AxiosRequestConfig) {
 		this.service = axios.create(config)
@@ -32,17 +40,19 @@ class RequestHttp {
 				config.headers!['X-token'] = getStorage()
 			}
 			if (!config.headers['Content-Type']) {
-				config.headers['Content-Type'] = 'multipart/form-data'
+				config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
 			}
+
 			return Promise.resolve(config)
 		}, (error: AxiosError) => {
+			showFailToast(error)
 			// 请求报错
 			Promise.reject(error)
 		})
 
 		this.service.interceptors.response.use((response: AxiosResponse) => {
 			const { msg, code } = response.data
-			console.log(code)
+			console.log(response.data)
 			if (response.status === 302) {
 				window.location.href = `/login?redirect=${window.location.pathname}`
 				return Promise.reject(msg)
@@ -51,14 +61,14 @@ class RequestHttp {
 				showFailToast(msg)
 				return Promise.reject(msg)
 			}
-			showSuccessToast(msg)
 			return Promise.resolve(response.data)
-		}, (err: AxiosError) => {
-			return Promise.reject(err)
+		}, (error: AxiosError) => {
+			showFailToast(error)
+			return Promise.reject(error)
 		})
 	}
 	get<T>(url: string, params?: Object): Promise<IResultData<T>> {
-		return this.service.get(url, params)
+		return this.service.get(url, { params })
 	}
 	post<T>(url: string, data: object): Promise<IResultData<T>> {
 		return this.service.post(url, data);

+ 89 - 0
src/views/Database/components/context-contain.vue

@@ -0,0 +1,89 @@
+<template>
+  <div class="box">
+    <slot name="head" :data="props" />
+    <div v-for="(d,i) in dataList" :key="i"> 
+      <div class="shareFile">
+        <div class="time">{{ d.addTime }}</div>
+        <slot name="share" :data="d" />
+      </div>
+      <file-content :title="d.title" :type="d.type" :shop-name="d.shopName" />
+    </div>
+    <div class="foot-btn">
+      <data-button
+        backgroundColor="#fff"
+        color="#909090"
+        :label="btnLabel"
+        icon="https://static.caimei365.com/app/mini-database/down.png"
+        @handle-emit="handleSeeMore"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { DDataBaseListAll, DEmit } from '@/types/views/database.type';
+import FileContent from "./file-content.vue";
+import { ref } from "vue";
+
+const pageNum = ref<number>(1)
+const emit = defineEmits<DEmit>()
+
+const props = defineProps<DDataBaseListAll>()
+
+const btnLabel = ref<string>("查看更多");
+
+const handleSeeMore = () => {
+  pageNum.value++
+  console.log(props.type, pageNum.value);
+  emit('handle-see-more', {
+    type: props.type,
+    pageNum: pageNum.value
+  })
+  console.log('点击了查看更多')
+}
+</script>
+
+<style scoped lang="scss">
+.box {
+  background: #fff;
+  width: 100%;
+  margin-bottom: 8px;
+  padding: 18px 15px 0 15px;
+  box-sizing: border-box;
+  .shareFile {
+    @include display-flex-between;
+    width: 100%;
+    .time {
+      font-size: $basicFS;
+      color: $basicColor-content;
+      font-weight: bold;
+    }
+  }
+  .foot-btn {
+    width: 100%;
+    height: 70px;
+    @include display-flex-center;
+    box-sizing: border-box;
+    padding-top: 4px;
+    :deep() {
+      .van-button {
+        width: 100px !important;
+        font-size: $basicFS-foot;
+        color: $basicColor-foot;
+        height: 30px;
+      }
+    }
+  }
+}
+:deep() {
+	.van-popup--center {
+		.van-swipe__track,
+		.van-swipe-item {
+			width: 100% !important;
+		}
+		.van-image-preview__index {
+			display: none;
+		}
+	}
+}
+</style>

+ 83 - 0
src/views/Database/components/context-head.vue

@@ -0,0 +1,83 @@
+<template>
+  <div>
+    <div class="title" v-if="storeType === '0'">{{ controlText }}</div>
+    <div v-if="type === '5'" class="enterprise">
+      <van-tabs v-model:active="active" shrink>
+        <van-tab
+          v-for="item in enterpriseOrIndividual"
+          :title="item.value"
+          :key="item.id"
+        />
+      </van-tabs>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {
+  ChangeTabEmit,
+  DFindParams,
+  DScrollTab,
+  tabList,
+} from "@/types/views/database.type";
+import { ref, computed, toRefs } from "vue";
+import { useTabStore } from '../../../store/tab/tab';
+
+const { type: storeType } = toRefs(useTabStore())
+
+const props = defineProps<{
+  type: ChangeTabEmit;
+}>();
+
+console.log("插槽传递的值为:", props);
+
+const enterpriseOrIndividual = [
+  { id: 0, value: "企业话术" },
+  { id: 1, value: "个人话术" },
+];
+
+const active = ref<number>(0);
+
+const controlText = computed<DFindParams<DScrollTab, "text">>(
+  () => tabList.filter((e) => e.type === props.type)[0].text
+);
+</script>
+
+<style scoped lang="scss">
+.title {
+  color: $basicColor-content;
+  font-weight: bold;
+  font-size: 16px;
+  font-family: Microsoft YaHei-Bold;
+  margin-bottom: 18px;
+}
+.enterprise {
+  margin-bottom: 24px;
+}
+:deep() {
+  .van-tabs__nav--line.van-tabs__nav--shrink,
+  .van-tabs__nav--line.van-tabs__nav--complete {
+    padding-left: 0;
+  }
+  .van-tabs--line .van-tabs__wrap {
+    height: 32px;
+  }
+  .van-tab--shrink {
+    padding: 0;
+    margin-right: 24px;
+    font-size: 13px;
+    font-weight: bold;
+    color: $basicColor-content;
+  }
+  .van-tabs__nav--line {
+    padding-bottom: 0;
+  }
+  .van-tabs__line {
+    bottom: 0;
+    background: $basicColor;
+  }
+  .van-tab--active {
+    color: $basicColor;
+  }
+}
+</style>

+ 54 - 0
src/views/Database/components/context-share.vue

@@ -0,0 +1,54 @@
+<template>
+	<div class="share" v-if="type === '5'">
+		<div class="show" @click.stop="handleDetail(props)">复制话术内容</div>
+		<div class="showNum" @click.stop="handleShare(props)">已使用:5次</div>
+	</div>
+	<div class="share" v-else>
+		<div class="show" @click.stop="handleDetail(props)">查看{{ controlText }}</div>
+		<div class="show" @click.stop="handleShare(props)">分享</div>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { DArchiveResultData } from '@/types/api/context.type';
+import { DFindParams, DScrollTab, tabList, DetailParams } from '@/types/views/database.type';
+import { computed } from 'vue';
+import { useRouter } from 'vue-router';
+
+const props = defineProps<DetailParams>()
+
+const router = useRouter()
+
+const controlText = computed<DFindParams<DScrollTab, "text">>(
+  () => tabList.filter((e) => e.type === props.type)[0].text
+);
+
+const handleDetail = ($event: DArchiveResultData) => {
+  router.push("/database/detail?id=" + $event.id + "&t=" + $event.type);
+  console.log($event.type);
+};
+const handleShare = ($event: DetailParams) => {
+  console.log($event);
+  console.log('点击了分享按钮')
+}
+</script>
+
+<style scoped lang="scss">
+.share {
+	display: flex;
+	align-items: center;
+	.show {
+		margin-left: 24px;
+		color: $basicColor;
+		font-size: $basicFS;
+	}
+	.showNum {
+		margin-left: 24px;
+		background: #F5F5F5;
+		padding: 3px 9px;
+		border-radius: 2px;
+		font-size: $basicFS-foot;
+		color: #666;
+	}
+}
+</style>

+ 43 - 0
src/views/Database/components/file-content.vue

@@ -0,0 +1,43 @@
+<template>
+  <div class="all-file">
+    <div class="container">
+			<video-img-content v-if="showVideoImgContent()" :title="title!" :waters="waters" :type="type" :content="content" />
+			<text-file-content v-else :title="title" :type="type" :content="content" :waters="waters" />
+		</div>
+		<div class="foot">
+			<div class="mark">随便看看</div>
+			<div class="mark">{{ shopName }}</div>
+			<div class="mark">{{ keywords }}</div>
+		</div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import VideoImgContent from './video-img-content.vue'
+import TextFileContent from './text-file-content.vue';
+import { DArchiveResultData } from '@/types/api/context.type';
+
+const props = defineProps<DArchiveResultData>()
+
+const showVideoImgContent = (): boolean => ["1", "2", "4"].indexOf(props.type as string) !== -1
+
+</script>
+
+<style lang="scss" scoped>
+.all-file {
+	width: 100%;
+	padding: 12px 0 9px 0;
+	margin-bottom: 14px;
+	border-bottom: 1px solid #E1E1E1;
+}
+.container {
+	margin-bottom: 19px;
+}
+.foot {
+	@include display-flex-between;
+	font-size: $basicFS-foot;
+	.mark {
+		color: $basicColor-foot;
+	}
+}
+</style>

+ 16 - 0
src/views/Database/components/high-light-text.vue

@@ -0,0 +1,16 @@
+<template>
+	<van-highlight :keywords="props.keywords" :source-string="props.text" v-if="keywords" />
+	<div v-else>{{ props.text }}</div>
+</template>
+
+<script setup lang="ts">
+const props = defineProps<{
+	keywords: string
+	text: string 
+}>()
+
+</script>
+
+<style scoped>
+
+</style>

+ 67 - 0
src/views/Database/components/scroll-tap-btn.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="scroll-tap-container">
+    <div class="scroll">
+      <data-button
+        v-for="i in tabList"
+        :key="i.type"
+        :label="i.text"
+        @handle-emit="handleChangeTab(i)"
+        :class="sType === i.type ? 'active' : ''"
+        backgroundColor="#fff"
+        color="#666666"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { toRefs } from 'vue';
+import { DScrollTab, DEmit, tabList } from '@/types/views/database.type';
+import { useTabStore } from '@/store/tab/tab';
+
+const { type: sType } = toRefs(useTabStore())
+
+const emit = defineEmits<DEmit>()
+const handleChangeTab = (event: DScrollTab): void => {
+	emit('handle-tab-emit', event)
+};
+
+</script>
+
+<style scoped lang="scss">
+.scroll-tap-container {
+  background: $bgColor;
+  width: 100vw;
+  height: 68px;
+  box-sizing: border-box;
+  display: flex;
+  align-items: center;
+  overflow: hidden;
+  .scroll {
+    width: auto;
+    overflow-x: scroll;
+    height: 34px;
+    white-space: nowrap;
+    padding-left: 18px;
+  }
+}
+::-webkit-scrollbar {
+  width: 0;
+  height: 0;
+  background-color: transparent;
+}
+:deep() {
+  .van-button {
+    width: 63px !important;
+    height: 34px !important;
+    margin-right: 12px;
+  }
+  .van-button--normal {
+    font-size: 13px;
+  }
+  .active {
+    background: $basicColor !important;
+    color: #fff !important;
+  }
+}
+</style>

+ 250 - 0
src/views/Database/components/search-head.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="search-head">
+    <van-search v-model="value" placeholder="请输入搜索关键词" @search="emit('handle-search-emit', value)" />
+    <van-dropdown-menu active-color="#FF5B00">
+      <van-dropdown-item
+			  active-color="#FF5B00"
+        :title="i.title"
+        ref="itemRef"
+        v-for="(i, o) in menuTypeOptions"
+        :key="o"
+        v-model="i.changeValue"
+        :options="i.type !== 'Double' ? i.options : []"
+				:class="[activeMenu === o ? 'activeMenu' : '']"
+				@close="handleDropdownClose"
+      >
+        <template v-if="o !== 3">
+          <van-search :disabled="o === 2" v-model="searchValue" placeholder="请输入搜索关键词" />
+        </template>
+        <template v-if="i.type === 'Double'">
+          <van-checkbox-group v-model="checked">
+            <van-cell-group inset>
+              <van-cell
+                v-for="(item, index) in i.options"
+                clickable
+                :key="index"
+                :title="item.text"
+                @click="toggle(item.value)"
+								:class="checked.indexOf(item.value) > -1 ? 'd-checked' : ''"
+              >
+                <template #right-icon>
+                  <van-checkbox
+                    :name="item.value"
+                    :ref="($event: VNodeRef) => ((checkboxRefs[item.value]) = $event)"
+                  />
+                </template>
+              </van-cell>
+            </van-cell-group>
+          </van-checkbox-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 { getLabelKeyList, getStoreList } from "@/api/context/context";
+import { CheckboxInstance } from 'vant';
+
+type menuOptions = Array<DMenuList<DMenu>>; // 菜单类型
+
+const activeMenu = ref<number>(0) // 切换tab
+const searchValue = ref<string>('') // 搜索条件
+const value = ref<string>(''); // 标题搜索
+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 emit = defineEmits<DEmit>()
+const handleDropdownClose = (): void => {
+	emit('handle-change-emit', {
+    labelIds: checked.value.join(),
+    productId: menuTypeOptions[1].changeValue!,
+    stageStatus: menuTypeOptions[2].changeValue!.toString()
+  })
+}
+
+const reqLabelKeyList = async () => {
+  const { data } = await getLabelKeyList({
+    pageNum: 1,
+    pageSize: 10,
+    v: ''
+  })
+  menuTypeOptions[0].options = data!.list!.map(e => ({
+    text: e.v,
+    value: Number(e.k)
+  }))
+}
+const reqStoreList = async () => {
+  const { data } = await getStoreList({
+    pageNum: 1,
+    pageSize: 10,
+    productName: ''
+  })
+  menuTypeOptions[1].options = data!.list!.map(e => ({
+    text: e.productName,
+    value: e.productId
+  }))
+}
+
+onMounted(async () => {
+  await reqLabelKeyList()
+  await reqStoreList()
+})
+// 组件更新
+onBeforeUpdate(() => {
+  checkboxRefs.value = [];
+});
+</script>
+
+<style scoped lang="scss">
+.search-head {
+  padding: 15px 12px 0 12px;
+  background-color: #fff;
+  box-sizing: border-box;
+}
+:deep() {
+  .van-search {
+    height: 38px;
+    font-size: 13px;
+    padding: 0;
+    border: 1px solid #e1e1e1;
+		.van-search__field {
+			padding: 0;
+		}
+    .van-search__content {
+      background: #fff;
+    }
+    .van-field__left-icon .van-icon {
+      width: 24px;
+      height: 24px;
+    }
+  }
+  .van-cell-group--inset {
+    margin: 0;
+  }
+  .van-dropdown-menu {
+    height: 50px;
+    padding-top: 20px;
+    box-sizing: border-box;
+  }
+  .van-dropdown-menu__bar {
+    box-shadow: none;
+    height: 30px;
+  }
+  .van-dropdown-menu__title {
+    font-size: 16px;
+    color: #333;
+    position: relative;
+  }
+	.van-cell {
+		padding: 7.5px;
+		.van-cell__title {
+			color: rgb(37, 1, 1);
+			font-size: 13px;
+		}
+	}
+	.van-checkbox__icon--checked .van-icon,
+	.van-checkbox__icon .van-icon {
+		background: none;
+		border: none;
+	}
+  .van-dropdown-menu__title::after {
+    opacity: 1;
+  }
+	.van-dropdown-item__option--active,
+	.van-dropdown-menu__title--active {
+		.van-cell__title,
+		.van-dropdown-menu__title::after {
+			color: $basicColor !important;
+		}
+	}
+
+  .van-dropdown-menu__title--active::before {
+    content: '';
+    position: absolute;
+    width: 30px;
+    height: 2px;
+    background: $basicColor;
+    bottom: -4px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+  .van-popup--top {
+    max-height: 50vh;
+    position: relative;
+    padding: 45px 5px 5px 5px;
+    .van-search {
+      position: absolute;
+      top: 24px;
+      left: 50%;
+      width: 96%;
+      height: 40px;
+      transform: translate(-50%, -50%);
+    }
+    .van-cell__title, .van-cell__value {
+      flex: auto;
+      width: 20px;
+    }
+    .van-cell__title {
+      width: 80%;
+    }
+  }
+}
+.d-checked {
+	:deep() {
+		.van-checkbox__icon--checked .van-icon,
+		.van-cell__title {
+			color: $basicColor;
+		}
+	}
+}
+.activeMenu {
+	color: $basicColor;
+}
+</style>

+ 53 - 0
src/views/Database/components/text-file-content.vue

@@ -0,0 +1,53 @@
+<template>
+	<div class="file">
+		<div class="image" v-if="type !== '5'">
+			<van-image
+				fit="contain"
+				src="https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg"
+			/>
+		</div>
+		<div class="title">
+			<div class="t1"><high-light-text :keywords="'标题'" :text="title!" /></div>
+			<div class="t2" v-if="!showFileContent()"><high-light-text :keywords="'以色列'" :text="title!" /></div>
+		</div>
+	</div>
+</template>
+
+<script lang="ts" setup>
+import highLightText from './high-light-text.vue';
+import { DArchiveResultData } from '@/types/api/context.type';
+
+const props = defineProps<DArchiveResultData>()
+
+const showFileContent = (): boolean => ["3", "6"].indexOf(props.type as string) !== -1
+</script>
+
+<style lang="scss" scoped>
+.file {
+	display: flex;
+	align-items: center;
+	.image {
+		width: 63px;
+		height: 63px;
+		@include display-flex-center;
+		margin-right: 12px;
+	}
+	.title {
+		font-size: $basicFS;
+		min-width: calc(100% - 75px);
+		display: flex;
+		justify-content: space-around;
+		flex-direction: column;
+		height:63px;
+		.t1 {
+			color: $basicColor-content;
+			@include webkit-line-clamp (1);
+		}
+		.t2 {
+			line-height: 21px;
+			color: $basicColor-foot;
+			@include webkit-line-clamp (2);
+		}
+	}
+}
+</style>

+ 109 - 0
src/views/Database/components/video-img-content.vue

@@ -0,0 +1,109 @@
+<template>
+  <div>
+    <div class="text-title">
+      <high-light-text :keywords="''" :text="props.title!" />
+    </div>
+    <div class="img-content" v-if="type === '1'">
+      <div class="item">
+        <van-image
+          v-for="(img, i) in waters"
+          :key="i"
+          fit="contain"
+          :src="img"
+          @click.native="shopImagePreviews(i)"
+        />
+      </div>
+    </div>
+    <div class="video-tontent" v-if="type === '2'">
+      <video
+        id="myVideoRef"
+        ref="myVideoRef"
+        class="video-js vjs-default-skin"
+        controls
+        autoplay
+        x5-video-player-fullscreen="true"
+        x5-video-player-type="h5"
+        controlslist="nodownload"
+      >
+        <source src="https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/07be2bc1cf6d4b649d694c0c81edd50d.mp4?Expires=1703755722&OSSAccessKeyId=LTAI4GBL3o4YkWnbKYgf2Xia&Signature=FkraWtEi6HmZNYoKvMgoNVsNbmU%3D" type="video/mp4" />
+      </video>
+    </div>
+    <div class="text-content" v-if="type === '4'">
+      <div v-html="content" />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import highLightText from "./high-light-text.vue";
+import { DArchiveResultData } from "@/types/api/context.type";
+import { showImagePreview } from "vant";
+
+const props = withDefaults(defineProps<DArchiveResultData>(), {
+  waters: () => ["https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg"],
+});
+
+const shopImagePreviews = (index: number) => {
+  console.log(index);
+  showImagePreview({
+    images: props.waters!,
+    startPosition: index,
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.text-title {
+  @include webkit-line-clamp(2);
+  font-size: $basicFS;
+  line-height: 21px;
+  color: $basicColor-content;
+  margin-bottom: 10px;
+}
+.img-content {
+  display: grid;
+  grid-template-columns: repeat(3fr);
+  grid-gap: 12px;
+  .item {
+    border: 1px solid #e1e1e1;
+    width: 106px;
+    height: 106px;
+  }
+}
+.video-tontent {
+  width: 100%;
+  height: 210px;
+  video {
+    height: 100%;
+    width: 100%;
+  }
+}
+.text-content {
+  width: 100%;
+  height: 221px;
+}
+video::-internal-media-controls-download-button {
+  display: none;
+}
+video::-webkit-media-controls-enclosure {
+  overflow: hidden;
+}
+video::-webkit-media-controls-panel {
+  width: calc(100% + 30px);
+}
+:deep() {
+  .van-image {
+    width: 100%;
+    height: 100%;
+  }
+  .van-popup--center {
+		.van-swipe__track,
+		.van-swipe-item {
+			width: 100% !important;
+		}
+		.van-image-preview__index {
+			display: none;
+		}
+	}
+}
+</style>

+ 84 - 0
src/views/Database/data-all/index.vue

@@ -0,0 +1,84 @@
+<template>
+  <div v-for="(data, i) in dataList" :key="i">
+    <context-contain
+      :type="data.type"
+      :data-list="data.dataList"
+      v-if="data.dataList.length > 0 && data.type !== '0'"
+      @handle-see-more="handleSeeMore"
+    >
+      <template #head="{ data }">
+        <context-head :type="data.type" />
+      </template>
+      <template #share="{ data }">
+        <context-share :type="data.type!" :id="data.id" />
+      </template>
+    </context-contain>
+    <div v-if="isEmpty && i === 0" class="empty">
+      暂无任何文件~
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, watchEffect, onMounted } from "vue";
+import contextContain from "../components/context-contain.vue";
+import { DDataBaseListAll, DetailParams, tabList } from "@/types/views/database.type";
+import contextHead from "../components/context-head.vue";
+import contextShare from "../components/context-share.vue";
+import { useRoute } from "vue-router";
+import { getArchiveList } from "@/api/context/context";
+import { IArchiveRequest } from "@/types/api/context.type"
+
+const route = useRoute();
+const dataList = ref<DDataBaseListAll[] | null>(null);
+const setNull = (t: any) => (t === "0" ? "" : t);
+const reqParams = computed<IArchiveRequest>(
+  () =>
+    ({
+      type: setNull(route.query.t),
+      title: route.query.sv,
+      productId: setNull(route.query.pId),
+      labelIds: route.query.lId,
+      stageStatus: setNull(route.query.ss),
+      allStatus: route.query.as,
+      pageNum: 1,
+    } as IArchiveRequest)
+);
+
+const isEmpty = ref<boolean>(false)
+const reqArchiveList = async (res?: DetailParams) => {
+  if (!res) {
+    const { data } = await getArchiveList({ ...reqParams.value });
+    dataList.value = tabList.map((e) => ({
+      type: e.type,
+      dataList: data!.filter((i) => i.type === e.type),
+    }));
+    isEmpty.value = data?.length === 0
+  } else {
+    const { data } = await getArchiveList({ ...reqParams.value, ...res! });
+    dataList.value![res.type]!.dataList = [...dataList.value![res.type]!.dataList, ...data!]
+    isEmpty.value = data?.length === 0
+  }
+};
+
+const handleSeeMore = ($event: DetailParams) => {
+  reqArchiveList($event)
+}
+watchEffect(() => {
+  reqArchiveList();
+  console.log(reqParams.value);
+});
+
+onMounted(() => {});
+</script>
+
+<style lang="scss" scoped>
+.empty {
+  width: 100%;
+  height: 135px;
+  background: #fff;
+  @include display-column-end;
+  font-size: $basicFS-foot;
+  color: #909090;
+}
+</style>

+ 179 - 0
src/views/Database/detail.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="detail">
+    <div class="other" v-if="type === '5'">个人话术<span>已使用:{{ form?.pv || 0 }}次</span></div>
+    <div class="time">{{ form?.addTime }}</div>
+    <div class="title">{{ form?.title }}</div>
+    <div class="text" v-if="type === '5'">
+      {{ form?.content }}
+    </div>
+    <div class="content" v-if="type !== '5'">
+			<div v-html="form?.content" v-if="type === '4'" />
+			<div class="img-content" v-if="type === '1'">
+				<div class="item">
+					<van-image
+						v-for="(img, i) in form?.waters"
+						:key="i"
+						fit="contain"
+						:src="img"
+						@click.native="shopImagePreviews(i)"
+					/>
+				</div>
+			</div>
+			<div class="video-tontent" v-if="type === '2'">
+				<video
+					id="myVideoRef"
+					ref="myVideoRef"
+					class="video-js vjs-default-skin"
+					controls
+					autoplay
+					x5-video-player-fullscreen="true"
+					x5-video-player-type="h5"
+					controlslist="nodownload"
+				>
+					<source src="https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/07be2bc1cf6d4b649d694c0c81edd50d.mp4?Expires=1703755722&OSSAccessKeyId=LTAI4GBL3o4YkWnbKYgf2Xia&Signature=FkraWtEi6HmZNYoKvMgoNVsNbmU%3D" type="video/mp4" />
+				</video>
+			</div>
+		</div>
+    <p class="foot-mark">随便看看</p>
+    <p class="foot-mark">{{ form?.shopName }}</p>
+    <p class="foot-mark">{{ form?.keywords }}</p>
+    <div class="data-btn">
+      <data-button
+        @handle-emit="handleClick(1)"
+        backgroundColor="#FFF"
+        color="#FF5B00"
+        label="查看文件"
+				v-if="type === '3'"
+      />
+      <data-button
+        @handle-emit="handleClick(1)"
+        backgroundColor="#FFF"
+        color="#FF5B00"
+        label="复制文本"
+				v-if="type === '5'"
+      />
+      <data-button
+        @handle-emit="handleClick(1)"
+        backgroundColor="#FFF"
+        color="#FF5B00"
+        label="分享"
+				v-if="type !== '5'"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { getArchiveFormDetails } from "@/api/context/context";
+import { DArchiveResultData } from "@/types/api/context.type";
+import { ChangeTabEmit } from "@/types/views/database.type";
+import { showImagePreview } from "vant";
+import { computed, onMounted, ref } from "vue";
+import { useRoute } from "vue-router";
+const route = useRoute();
+
+const form = ref<DArchiveResultData>()
+
+const handleClick = ($event: number) => {
+  console.log($event);
+};
+
+const id = computed<string>(() => String(route.query.id));
+const type = computed<ChangeTabEmit>(() => route.query.t as ChangeTabEmit);
+
+const getArchiveForm = async () => {
+  const { data } = await getArchiveFormDetails({
+    id: id.value,
+    userId: "",
+  });
+	form.value = data
+	console.log(data);
+};
+const shopImagePreviews = (index: number) => {
+  console.log(index);
+  showImagePreview({
+    images: form.value?.waters!,
+    startPosition: index,
+  });
+};
+
+onMounted(() => {
+	getArchiveForm()
+});
+</script>
+
+<style scoped lang="scss">
+.detail {
+  padding: 24px 15px;
+  .other {
+    font-size: 15px;
+    color: $basicColor-content;
+    margin-bottom: 12px;
+    font-weight: bold;
+    display: flex;
+    align-items: center;
+    span {
+      background: #f5f5f5;
+      color: #666;
+      padding: 5px;
+      margin-left: 10px;
+      font-size: $basicFS-foot;
+      border-radius: 2px;
+    }
+  }
+  .time {
+    font-size: $basicFS;
+    color: $basicColor-content;
+    margin-bottom: 12px;
+    font-weight: bold;
+  }
+  .title {
+    font-size: $basicFS;
+    color: $basicColor-content;
+    margin-bottom: 8px;
+  }
+  .text {
+    font-size: $basicFS;
+    color: $basicColor-foot;
+    line-height: 21px;
+    margin-bottom: 24px;
+  }
+	.content {
+		margin-bottom: 18px;
+		.img-content {
+			display: grid;
+			grid-template-columns: repeat(3fr);
+			grid-gap: 12px;
+			.item {
+				border: 1px solid #e1e1e1;
+				width: 106px;
+				height: 106px;
+			}
+		}
+		.video-tontent {
+			width: 100%;
+			height: 210px;
+			video {
+				height: 100%;
+				width: 100%;
+			}
+		}
+	}
+  .foot-mark {
+    color: $basicColor-foot;
+    font-size: $basicFS-foot;
+    margin-bottom: 9px;
+  }
+  .data-btn {
+    margin-top: 35px;
+    padding: 0 13px;
+  }
+}
+:deep() {
+  .van-button {
+    border: 1px solid $basicColor;
+    border-radius: 1px;
+		margin-bottom: 12px;
+  }
+}
+</style>

+ 0 - 10
src/views/Database/index.type.ts

@@ -1,10 +0,0 @@
-type DataType = 1 | 2 | 3
-
-export interface IDataBaseCell {
-  title: string;
-  value?: string;
-  isLink: boolean;
-  type: DataType
-}
-
-

+ 63 - 79
src/views/Database/index.vue

@@ -1,92 +1,76 @@
 <template>
-  <div>
-    <van-cell-group>
-      <van-cell
-        :title="item.title"
-        :value="item.value"
-        is-link
-        v-for="(item, index) in dataBaseCellGroup"
-        :key="index"
-				@click="handleCellClick(item.type)"
-      />
-    </van-cell-group>
+  <div class="head">
+    <search-head @handle-change-emit="handleChange" @handle-search-emit="handleSearch" />
+    <scroll-tap-btn @handle-tab-emit="handleTabEmit" />
+  </div>
+  <div class="container">
+    <router-view />
   </div>
 </template>
 
 <script setup lang="ts">
+import { useTabStore } from "@/store/tab/tab";
+import SearchHead from "./components/search-head.vue";
+import ScrollTapBtn from "./components/scroll-tap-btn.vue";
+import type {
+  SearchEmitParams,
+  ChangeEmitParams,
+  DScrollTab,
+} from "@/types/views/database.type";
+import useStatisticalTime from "@/Hooks/useStatisticalTime";
+import { onUnmounted, ref } from "vue";
 import { useRouter } from "vue-router";
-
-import { reactive } from "vue";
-import type { IDataBaseCell } from './index.type';
-
-const dataBaseCellGroup = reactive<Array<IDataBaseCell>>([
-  {
-    title: "文件预览",
-    value: "",
-    isLink: true,
-    type: 1,
-  },
-  {
-    title: "视频预览",
-    value: "",
-    isLink: true,
-    type: 2,
-  },
-  {
-    title: "图片预览",
-    value: "",
-    isLink: true,
-    type: 3,
-  },
-]);
-
-
+import { DTabStore } from "@/store/tab/tab.type";
+const tabStore = useTabStore();
 const router = useRouter();
-
-const showPdfPreview = (): void => {
-  router.push({
-    path: "/preview",
-    query: {
-      type: 1,
-      src:
-        "https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/d99a0fa229524d1496925e2328a77b70.pdf",
-    },
-  });
+const params = ref<DTabStore>({
+  type: "0",
+  labelIds: "",
+  stageStatus: "",
+  productId: 0,
+  searchValue: "",
+});
+const routerLink = () => {
+  tabStore.updatedTabStore(params.value);
+  router.push(
+    `/database/index?t=${tabStore.type}&lId=${tabStore.labelIds}&sv=${tabStore.searchValue}&pId=${tabStore.productId}&ss=${tabStore.stageStatus}`
+  );
 };
-
-const showVideoPreview = (): void => {
-  router.push({
-    path: "/preview",
-    query: {
-      type: 2,
-      src:
-        "https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/07be2bc1cf6d4b649d694c0c81edd50d.mp4",
-    },
-  });
+const handleSearch = (event: SearchEmitParams) => {
+  params.value.searchValue = event;
+  routerLink();
 };
-
-const showImagePreview = () => {
-  router.push({
-    path: "/preview",
-    query: {
-      type: 3,
-      src:
-        "https://caimei-oss.oss-cn-shenzhen.aliyuncs.com/beta/archiveFile/d99a0fa229524d1496925e2328a77b70.pdf",
-    },
-  });
+const handleChange = (event: ChangeEmitParams) => {
+  params.value = { ...params.value, ...event };
+  routerLink();
 };
-interface ICellList {
-  [key: string | number]: () => void
-}
-const handleCellClick = (type: number) => {
-  const cellList: ICellList = {
-    1: () => showPdfPreview(),
-    2: () => showVideoPreview(),
-    3: () => showImagePreview()
-  }
-  cellList[type]()
-}
+const handleTabEmit = (event: DScrollTab): void => {
+  params.value.type = event.type;
+  routerLink();
+};
+
+const statistical = useStatisticalTime((time) => {
+  const t = Math.floor(time / 1000);
+  console.log("时长为:", t);
+  localStorage.setItem("spentTime", t.toString());
+});
 
+onUnmounted(() => {
+  statistical();
+});
 </script>
 
-<style scoped></style>
+<style scoped lang="scss">
+.head {
+  position: fixed;
+  top: 0;
+  left: 0;
+  z-index: 999;
+  background: #fff;
+}
+
+.container {
+  margin-top: 170px;
+  background: #f7f7f7;
+}
+</style>

+ 0 - 13
src/views/Home/index.vue

@@ -1,13 +0,0 @@
-<template>
-	<div>
-		这个是home
-	</div>
-</template>
-
-<script setup lang="ts">
-
-</script>
-
-<style scoped>
-
-</style>

+ 79 - 51
src/views/Login/index.vue

@@ -1,67 +1,95 @@
 <template>
   <div class="login">
-		<van-form @submit="onSubmit">
-			<van-cell-group inset>
-				<van-field
-					v-model="mobileOrEmail"
-					name="mobileOrEmail"
-					label="用户名"
-					placeholder="用户名"
-					:rules="[{ required: true, message: '请填写用户名' }]"
-				/>
-				<van-field
-					v-model="password"
-					type="password"
-					name="password"
-					label="密码"
-					placeholder="密码"
-					autocomplete="off"
-					:rules="[{ required: true, message: '请填写密码' }]"
-				/>
-			</van-cell-group>
-			<div style="margin: 16px">
-				<van-button round block type="primary" native-type="submit"> 提交 </van-button>
-			</div>
-		</van-form>
-	</div>
+    <van-form @submit="onSubmit">
+      <van-cell-group inset>
+        <van-field
+          v-model="form.mobileOrEmail"
+          name="mobileOrEmail"
+          left-icon="https://static.caimei365.com/app/mini-database/phone.png"
+          placeholder="用户名"
+          autocomplete="off"
+        />
+        <van-field
+          v-model="form.password"
+          type="password"
+          name="password"
+          left-icon="https://static.caimei365.com/app/mini-database/password.png"
+          placeholder="密码"
+          autocomplete="off"
+        />
+      </van-cell-group>
+      <div style="margin: 52px 30px">
+        <data-button label="登录" type="primary" :disabled="disabled" @handle-emit="onSubmit" />
+      </div>
+    </van-form>
+  </div>
 </template>
 
 <script setup lang="ts">
-import { ref } from "vue";
-import { useUserInfoState } from '@/store/user/user';
-import { useRoute, useRouter } from 'vue-router';
-import { ILogin } from '@/api/user/index.type';
+import { ref, computed } from "vue";
+import { useUserInfoState } from "@/store/user/user";
+//import { useRouter } from "vue-router";
+import { ILogin } from "@/types/api/user.type";
 
-const router = useRouter()
-const route = useRoute()
-console.log(router, route)
-const { login } = useUserInfoState()
-const mobileOrEmail = ref("");
-const password = ref("");
+//const router = useRouter();
 
-const onSubmit = async (values: ILogin) => {
-	const { data, code } = await login(values)
-	console.log(data)
-	if (code === 0) {
-		console.log(1, data)
-	}
-	else {
-		console.log(2)
-	}
+const { login } = useUserInfoState();
+
+const form = ref<ILogin>({
+  mobileOrEmail: "",
+  password: "",
+  isUnion: 1
+});
+
+const disabled = computed<boolean>(() => (!form.value.mobileOrEmail || !form.value.password))
+
+const onSubmit = async () => {
+  if (!disabled.value) {
+    const { data, code } = await login(form.value);
+    console.log(data);
+    if (code === 0) {
+      console.log(1, data);
+    } else {
+      console.log(2);
+    }
+  }
 };
 </script>
 
 <style scoped lang="scss">
 .login {
-	width: 100vw;
-	height: 100vh;
-	padding: 20vw 0;
-	display: flex;
-	justify-content: center;
-	box-sizing: border-box;
+  width: 100vw;
+  height: 100vh;
+  padding: 20vw 0;
+  display: flex;
+  justify-content: center;
+  box-sizing: border-box;
 }
 
-:deep(.van-form) {
-	width: 400px;
+.van-field {
+  border-bottom: 1px solid #e1e1e1;
+  height: 52px;
+  display: flex;
+  align-items: center;
+  padding: 0;
+}
+.van-cell-group--inset {
+  width: 315px;
+  margin: 0 auto;
+}
+:deep() {
+	.van-form {
+		.van-field__left-icon {
+			margin-right: 14px;
+			.van-icon {
+				width: 16px;
+				height: 20px;
+			}
+		}
+		width: 400px;
+	}
+	.van-field__control {
+		font-size: 13px;
+	}
 }
 </style>

+ 0 - 23
src/views/Preview/components/layout.vue

@@ -1,23 +0,0 @@
-<template>
-	<div>
-		<Suspense>
-			<template #default>
-				<slot name="container" />
-			</template>
-			<template #fallback>
-				<div>
-					加载中...
-				</div>
-			</template>
-		</Suspense>
-	</div>
-</template>
-
-<script lang="ts" setup>
-
-
-</script>
-
-<style lang="scss" scoped>
-
-</style>

+ 0 - 4
src/views/Preview/index.type.ts

@@ -1,4 +0,0 @@
-export type IProps = {
-	type: number
-	src: string
-}

+ 6 - 21
src/views/Preview/index.vue

@@ -1,28 +1,13 @@
 <template>
-	<layout-preview>
-		<template #container>
-			<template v-if="route.query?.type === '1'">
-				<pdf-preview :url="(route.query.src as string)" :isPermi="isPermi" />
-				<permi-mode />
-			</template>
-			<template v-else-if="route.query.type === '2'">
-				<video-preview :url="(route.query.src as string)" :isPermi="isPermi" />
-			</template>
-			<template v-else>
-				<image-preview :url="(route.query.src as string)" :isPermi="isPermi" />
-			</template>
-		</template>
-	</layout-preview>
+	<video-preview></video-preview>
+	<pdf-preview></pdf-preview>
+	<image-preview></image-preview>
 </template>
 
 <script lang="ts" setup>
-import LayoutPreview from './components/layout.vue'
-import { usePermission } from '@/Hooks/usePermission/usePermission'
-import { useRoute } from 'vue-router';
-
-const route = useRoute()
-
-const { isPermi, PermiMode } = usePermission() // 权限hook
+//import { usePermission } from '@/Hooks/usePermission/usePermission'
+//import { useRoute } from 'vue-router';
+//const { isPermi, PermiMode } = usePermission() // 权限hook
 
 
 </script>