Przeglądaj źródła

✨ feat: 广告管理<SP>: 新增顶部搜索初版, 修改api为post; 主题: 默认关闭Tagsview

WanGxC 1 rok temu
rodzic
commit
4f0da0c2c3

+ 136 - 136
src/stores/themeConfig.ts

@@ -1,4 +1,4 @@
-import { defineStore } from 'pinia';
+import { defineStore } from 'pinia'
 
 /**
  * 布局配置
@@ -9,148 +9,148 @@ import { defineStore } from 'pinia';
  * 2、或者点击布局配置最底部 `一键恢复默认` 按钮即可看到效果
  */
 export const useThemeConfig = defineStore('themeConfig', {
-	state: (): ThemeConfigState => ({
-		themeConfig: {
-			// 是否开启布局配置抽屉
-			isDrawer: false,
+  state: (): ThemeConfigState => ({
+    themeConfig: {
+      // 是否开启布局配置抽屉
+      isDrawer: false,
 
-			/**
-			 * 全局主题
-			 */
-			// 默认 primary 主题颜色
-			primary: '#409eff',
-			// 是否开启深色模式
-			isIsDark: false,
+      /**
+       * 全局主题
+       */
+      // 默认 primary 主题颜色
+      primary: '#409eff',
+      // 是否开启深色模式
+      isIsDark: false,
 
-			/**
-			 * 顶栏设置
-			 */
-			// 默认顶栏导航背景颜色
-			topBar: '#ffffff',
-			// 默认顶栏导航字体颜色
-			topBarColor: '#606266',
-			// 是否开启顶栏背景颜色渐变
-			isTopBarColorGradual: false,
+      /**
+       * 顶栏设置
+       */
+      // 默认顶栏导航背景颜色
+      topBar: '#ffffff',
+      // 默认顶栏导航字体颜色
+      topBarColor: '#606266',
+      // 是否开启顶栏背景颜色渐变
+      isTopBarColorGradual: false,
 
-			/**
-			 * 菜单设置
-			 */
-			// 默认菜单导航背景颜色
-			menuBar: '#334054',
-			// 默认菜单导航字体颜色
-			menuBarColor: '#eaeaea',
-			// 默认菜单高亮背景色
-			menuBarActiveColor: 'rgba(0, 0, 0, 0.2)',
-			// 是否开启菜单背景颜色渐变
-			isMenuBarColorGradual: false,
+      /**
+       * 菜单设置
+       */
+      // 默认菜单导航背景颜色
+      menuBar: '#334054',
+      // 默认菜单导航字体颜色
+      menuBarColor: '#eaeaea',
+      // 默认菜单高亮背景色
+      menuBarActiveColor: 'rgba(0, 0, 0, 0.2)',
+      // 是否开启菜单背景颜色渐变
+      isMenuBarColorGradual: false,
 
-			/**
-			 * 分栏设置
-			 */
-			// 默认分栏菜单背景颜色
-			columnsMenuBar: '#334054',
-			// 默认分栏菜单字体颜色
-			columnsMenuBarColor: '#e6e6e6',
-			// 是否开启分栏菜单背景颜色渐变
-			isColumnsMenuBarColorGradual: false,
-			// 是否开启分栏菜单鼠标悬停预加载(预览菜单)
-			isColumnsMenuHoverPreload: false,
+      /**
+       * 分栏设置
+       */
+      // 默认分栏菜单背景颜色
+      columnsMenuBar: '#334054',
+      // 默认分栏菜单字体颜色
+      columnsMenuBarColor: '#e6e6e6',
+      // 是否开启分栏菜单背景颜色渐变
+      isColumnsMenuBarColorGradual: false,
+      // 是否开启分栏菜单鼠标悬停预加载(预览菜单)
+      isColumnsMenuHoverPreload: false,
 
-			/**
-			 * 界面设置
-			 */
-			// 是否开启菜单水平折叠效果
-			isCollapse: false,
-			// 是否开启菜单手风琴效果
-			isUniqueOpened: true,
-			// 是否开启固定 Header
-			isFixedHeader: true,
-			// 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
-			isFixedHeaderChange: false,
-			// 是否开启经典布局分割菜单(仅经典布局生效)
-			isClassicSplitMenu: false,
-			// 是否开启自动锁屏
-			isLockScreen: false,
-			// 开启自动锁屏倒计时(s/秒)
-			lockScreenTime: 30,
+      /**
+       * 界面设置
+       */
+      // 是否开启菜单水平折叠效果
+      isCollapse: false,
+      // 是否开启菜单手风琴效果
+      isUniqueOpened: true,
+      // 是否开启固定 Header
+      isFixedHeader: true,
+      // 初始化变量,用于更新菜单 el-scrollbar 的高度,请勿删除
+      isFixedHeaderChange: false,
+      // 是否开启经典布局分割菜单(仅经典布局生效)
+      isClassicSplitMenu: false,
+      // 是否开启自动锁屏
+      isLockScreen: false,
+      // 开启自动锁屏倒计时(s/秒)
+      lockScreenTime: 30,
 
-			/**
-			 * 界面显示
-			 */
-			// 是否开启侧边栏 Logo
-			isShowLogo: true,
-			// 初始化变量,用于 el-scrollbar 的高度更新,请勿删除
-			isShowLogoChange: false,
-			// 是否开启 Breadcrumb,强制经典、横向布局不显示
-			isBreadcrumb: true,
-			// 是否开启 Tagsview
-			isTagsview: true,
-			// 是否开启 Breadcrumb 图标
-			isBreadcrumbIcon: true,
-			// 是否开启 Tagsview 图标
-			isTagsviewIcon: true,
-			// 是否开启 TagsView 缓存
-			isCacheTagsView: true,
-			// 是否开启 TagsView 拖拽
-			isSortableTagsView: true,
-			// 是否开启 TagsView 共用
-			isShareTagsView: false,
-			// 是否开启 Footer 底部版权信息
-			isFooter: true,
-			// 是否开启灰色模式
-			isGrayscale: false,
-			// 是否开启色弱模式
-			isInvert: false,
-			// 是否开启水印
-			isWartermark: false,
-			// 水印文案
-			wartermarkText: '',
+      /**
+       * 界面显示
+       */
+      // 是否开启侧边栏 Logo
+      isShowLogo: true,
+      // 初始化变量,用于 el-scrollbar 的高度更新,请勿删除
+      isShowLogoChange: false,
+      // 是否开启 Breadcrumb,强制经典、横向布局不显示
+      isBreadcrumb: true,
+      // 是否开启 Tagsview
+      isTagsview: false,
+      // 是否开启 Breadcrumb 图标
+      isBreadcrumbIcon: true,
+      // 是否开启 Tagsview 图标
+      isTagsviewIcon: true,
+      // 是否开启 TagsView 缓存
+      isCacheTagsView: true,
+      // 是否开启 TagsView 拖拽
+      isSortableTagsView: true,
+      // 是否开启 TagsView 共用
+      isShareTagsView: false,
+      // 是否开启 Footer 底部版权信息
+      isFooter: true,
+      // 是否开启灰色模式
+      isGrayscale: false,
+      // 是否开启色弱模式
+      isInvert: false,
+      // 是否开启水印
+      isWartermark: false,
+      // 水印文案
+      wartermarkText: '',
 
-			/**
-			 * 其它设置
-			 */
-			// Tagsview 风格:可选值"<tags-style-one|tags-style-four|tags-style-five>",默认 tags-style-five
-			// 定义的值与 `/src/layout/navBars/tagsView/tagsView.vue` 中的 class 同名
-			tagsStyle: 'tags-style-one',
-			// 主页面切换动画:可选值"<slide-right|slide-left|opacitys>",默认 slide-right
-			animation: 'slide-right',
-			// 分栏高亮风格:可选值"<columns-round|columns-card>",默认 columns-round
-			columnsAsideStyle: 'columns-round',
-			// 分栏布局风格:可选值"<columns-horizontal|columns-vertical>",默认 columns-horizontal
-			columnsAsideLayout: 'columns-vertical',
+      /**
+       * 其它设置
+       */
+      // Tagsview 风格:可选值"<tags-style-one|tags-style-four|tags-style-five>",默认 tags-style-five
+      // 定义的值与 `/src/layout/navBars/tagsView/tagsView.vue` 中的 class 同名
+      tagsStyle: 'tags-style-one',
+      // 主页面切换动画:可选值"<slide-right|slide-left|opacitys>",默认 slide-right
+      animation: 'slide-right',
+      // 分栏高亮风格:可选值"<columns-round|columns-card>",默认 columns-round
+      columnsAsideStyle: 'columns-round',
+      // 分栏布局风格:可选值"<columns-horizontal|columns-vertical>",默认 columns-horizontal
+      columnsAsideLayout: 'columns-vertical',
 
-			/**
-			 * 布局切换
-			 * 注意:为了演示,切换布局时,颜色会被还原成默认,代码位置:/@/layout/navBars/breadcrumb/setings.vue
-			 * 中的 `initSetLayoutChange(设置布局切换,重置主题样式)` 方法
-			 */
-			// 布局切换:可选值"<defaults|classic|transverse|columns>",默认 defaults
-			layout: 'defaults',
+      /**
+       * 布局切换
+       * 注意:为了演示,切换布局时,颜色会被还原成默认,代码位置:/@/layout/navBars/breadcrumb/setings.vue
+       * 中的 `initSetLayoutChange(设置布局切换,重置主题样式)` 方法
+       */
+      // 布局切换:可选值"<defaults|classic|transverse|columns>",默认 defaults
+      layout: 'defaults',
 
-			/**
-			 * 后端控制路由
-			 */
-			// 是否开启后端控制路由
-			isRequestRoutes: true,
+      /**
+       * 后端控制路由
+       */
+      // 是否开启后端控制路由
+      isRequestRoutes: true,
 
-			/**
-			 * 全局网站标题 / 副标题
-			 */
-			// 网站主标题(菜单导航、浏览器当前网页标题)
-			globalTitle: 'Ansjer',
-			// 网站副标题(登录页顶部文字)
-			globalViceTitle: 'Ansjer',
-			// 网站副标题(登录页顶部文字)
-			globalViceTitleMsg: '广告管理系统',
-			// 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
-			globalI18n: 'zh-cn',
-			// 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'
-			globalComponentSize: 'default',
-		},
-	}),
-	actions: {
-		setThemeConfig(data: ThemeConfigState) {
-			this.themeConfig = data.themeConfig;
-		},
-	},
-});
+      /**
+       * 全局网站标题 / 副标题
+       */
+      // 网站主标题(菜单导航、浏览器当前网页标题)
+      globalTitle: 'Ansjer',
+      // 网站副标题(登录页顶部文字)
+      globalViceTitle: 'Ansjer',
+      // 网站副标题(登录页顶部文字)
+      globalViceTitleMsg: '广告管理系统',
+      // 默认初始语言,可选值"<zh-cn|en|zh-tw>",默认 zh-cn
+      globalI18n: 'zh-cn',
+      // 默认全局组件大小,可选值"<large|'default'|small>",默认 'large'
+      globalComponentSize: 'default',
+    },
+  }),
+  actions: {
+    setThemeConfig(data: ThemeConfigState) {
+      this.themeConfig = data.themeConfig
+    },
+  },
+})

+ 47 - 0
src/views/adManage/sp/TopFilter/PopoverFilter/index.vue

@@ -0,0 +1,47 @@
+<script setup>
+import { onMounted } from 'vue'
+import { getProductSelect } from '../api'
+
+const isVisible = ref(false)
+
+function handlePopover() {
+  isVisible.value = !isVisible.value
+}
+
+const productFilterInput = ref('')
+const productFilterSelect = ref('')
+const productFilterOptions = ref([])
+
+async function fetchProductSelect() {
+  try {
+    const response = await getProductSelect()
+    productFilterOptions.value = response.data
+    productFilterSelect.value = response.data[0].value
+  } catch (error) {
+    console.log('error:', error)
+  }
+}
+
+onMounted(() => {
+  fetchProductSelect()
+})
+</script>
+
+<template>
+  <div style="max-width: 350px">
+    <el-popover :visible="isVisible" placement="bottom-start" title="Title" :width="1000">
+      <template #reference>
+        <el-input v-model="productFilterInput" @click="handlePopover" style="width: 350px" placeholder="Please input">
+          <template #prepend>
+            <el-select v-model="productFilterSelect" placeholder="Select" style="width: 115px">
+              <el-option v-for="item in productFilterOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </template>
+        </el-input>
+      </template>
+      <div class="flex"></div>
+    </el-popover>
+  </div>
+</template>
+
+<style scoped></style>

+ 10 - 0
src/views/adManage/sp/TopFilter/api.ts

@@ -0,0 +1,10 @@
+import { request } from '/@/utils/service'
+
+export const apiPrefix = '/api/ad_manage/sp/search'
+
+export function getProductSelect() {
+  return request({
+    url: apiPrefix + '/item',
+    method: 'GET',
+  })
+}

+ 9 - 0
src/views/adManage/sp/TopFilter/index.vue

@@ -0,0 +1,9 @@
+<script setup>
+import PopoverFiler from './PopoverFilter/index.vue'
+</script>
+
+<template>
+  <PopoverFiler v-model="isVisible"></PopoverFiler>
+</template>
+
+<style scoped></style>

+ 55 - 63
src/views/adManage/sp/campaigns/api.ts

@@ -1,84 +1,76 @@
-import { request } from '/@/utils/service';
-import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+import { request } from '/@/utils/service'
+import { UserPageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud'
 
-export const apiPrefix = '/api/ad_manage/spcampaigns/';
+export const apiPrefix = '/api/ad_manage/spcampaigns/'
 export function GetList(query: UserPageQuery) {
-    return request({
-        url: apiPrefix,
-        method: 'get',
-        params: query,
-    })
+  return request({
+    url: apiPrefix + 'list',
+    method: 'post',
+    data: query,
+  })
 }
 export function GetObj(id: any) {
-    return request({
-        url: apiPrefix + id + "/",
-        method: 'get',
-    });
+  return request({
+    url: apiPrefix + id + '/',
+    method: 'post',
+  })
 }
-
 export function AddObj(obj: AddReq) {
-    return request({
-        url: apiPrefix,
-        method: 'post',
-        data: obj,
-    });
+  return request({
+    url: apiPrefix,
+    method: 'post',
+    data: obj,
+  })
 }
-
 export function UpdateObj(obj: EditReq) {
-    return request({
-        url: apiPrefix + obj.id + '/',
-        method: 'put',
-        data: obj,
-    });
+  return request({
+    url: apiPrefix + obj.id + '/',
+    method: 'put',
+    data: obj,
+  })
 }
-
 export function DelObj(id: DelReq) {
-    return request({
-        url: apiPrefix + id + '/',
-        method: 'delete',
-        data: { id },
-    });
+  return request({
+    url: apiPrefix + id + '/',
+    method: 'delete',
+    data: { id },
+  })
 }
-
 export function getCardData(query: UserPageQuery) {
-    return request({
-        url: apiPrefix + "total/",
-        method: 'GET',
-        params: query
-    })
+  return request({
+    url: apiPrefix + 'total',
+    method: 'post',
+    data: query,
+  })
 }
-
 export function getLineData(query: UserPageQuery) {
-    query["dateRangeType"] = "D"
-    return request({
-        url: apiPrefix + "daily/",
-        method: 'GET',
-        params: query
-    })
+  query['dateRangeType'] = 'D'
+  return request({
+    url: apiPrefix + 'daily',
+    method: 'post',
+    data: query,
+  })
 }
-
 export function getLineWeekData(query: UserPageQuery) {
-    query["dateRangeType"] = "W"
-    return request({
-        url: apiPrefix + "daily/",
-        method: 'GET',
-        params: query
-    })
+  query['dateRangeType'] = 'W'
+  return request({
+    url: apiPrefix + 'daily',
+    method: 'post',
+    data: query,
+  })
 }
-
 export function getLineMonthData(query: UserPageQuery) {
-    query["dateRangeType"] = "M"
-    return request({
-        url: apiPrefix + "daily/",
-        method: 'GET',
-        params: query
-    })
+  query['dateRangeType'] = 'M'
+  return request({
+    url: apiPrefix + 'daily',
+    method: 'post',
+    data: query,
+  })
 }
-
 export function getAdStructureData(query: UserPageQuery) {
-    return request({
-        url: apiPrefix + "structure/",
-        method: 'GET',
-        params: query
-    })
+  return request({
+    url: apiPrefix + 'structure',
+    method: 'post',
+    data: query,
+  })
 }

+ 51 - 53
src/views/adManage/sp/index.vue

@@ -1,78 +1,76 @@
 <script lang="ts" setup>
-import { ref, onBeforeMount, Ref, watch, provide } from 'vue'
-import { useShopInfo } from '/@/stores/shopInfo'
-import { usePublicData } from '/@/stores/publicData'
 import { storeToRefs } from 'pinia'
-import { GetAllPortfolios } from '/@/views/adManage/portfolios/api'
-import DateRangePicker from '/@/components/DateRangePicker/index.vue'
+import { Ref, onBeforeMount, provide, ref } from 'vue'
+import AdvertisedProducts from './advertisedProducts/index.vue'
 import Campaigns from './campaigns/index.vue'
 import Keywords from './keywords/index.vue'
-import Targets from './targets/index.vue'
-import SearchTerm from './searchTerm/index.vue'
-import AdvertisedProducts from './advertisedProducts/index.vue'
-import PurchasedOtherProducts from './purchasedOtherProducts/index.vue'
 import Placement from './placement/index.vue'
+import PurchasedOtherProducts from './purchasedOtherProducts/index.vue'
+import SearchTerm from './searchTerm/index.vue'
+import Targets from './targets/index.vue'
+import DateRangePicker from '/@/components/DateRangePicker/index.vue'
+import { usePublicData } from '/@/stores/publicData'
+import { GetAllPortfolios } from '/@/views/adManage/portfolios/api'
+import TopFilter from './TopFilter/index.vue'
 
 // const shopInfo = useShopInfo()
 const publicData = usePublicData()
 const selectedPortfolios: Ref<string[]> = ref([])
 const portfolios: Ref<Portfolio[]> = ref([])
 const { dateRange } = storeToRefs(publicData)
+provide('dateRange', dateRange)
+
 const tabActiveName = ref('Campaigns')
 const tabs = [
-	{ label: '广告活动', name: 'Campaigns' },
-	{ label: '关键词投放', name: 'Keywords' },
-	{ label: '商品投放', name: 'Targets' },
-	{ label: '推广商品', name: 'AdvertisedProducts' },
-	{ label: '购买的其他商品', name: 'PurchasedOtherProducts' },
-	{ label: '搜索词', name: 'SearchTerm' },
-	{ label: '广告位', name: 'Placement' }
+  { label: '广告活动', name: 'Campaigns' },
+  { label: '关键词投放', name: 'Keywords' },
+  { label: '商品投放', name: 'Targets' },
+  { label: '推广商品', name: 'AdvertisedProducts' },
+  { label: '购买的其他商品', name: 'PurchasedOtherProducts' },
+  { label: '搜索词', name: 'SearchTerm' },
+  { label: '广告位', name: 'Placement' },
 ]
 const tabsComponents: any = {
-	Campaigns,
-	Keywords,
-	Targets,
-	AdvertisedProducts,
-	PurchasedOtherProducts,
-	SearchTerm,
-	Placement
+  Campaigns,
+  Keywords,
+  Targets,
+  AdvertisedProducts,
+  PurchasedOtherProducts,
+  SearchTerm,
+  Placement,
 }
 
-provide('dateRange', dateRange)
-
 onBeforeMount(async () => {
-	const resp: APIResponseData = await GetAllPortfolios()
-	portfolios.value = resp.data
+  const resp: APIResponseData = await GetAllPortfolios()
+  portfolios.value = resp.data
 })
-
 </script>
 
 <template>
-	<div class="asj-container">
-		<div class="public-search">
-			<DateRangePicker v-model="dateRange"></DateRangePicker>
-			<el-select
-				v-model="selectedPortfolios"
-				placeholder="广告组合"
-				clearable
-				multiple
-				style="width: 400px"
-				collapse-tags
-				collapse-tags-tooltip
-				:max-collapse-tags="3"
-				disabled="true"
-			>
-				<el-option v-for="info of portfolios" :label="info.name" :value="info.portfolioId"></el-option>
-			</el-select>
-		</div>
-
-		<div class="asj-tabs">
-			<div v-for="tab of tabs" :key="tab.name" :class="['asj-tab', { active: tabActiveName === tab.name }]" @click="tabActiveName = tab.name">
-				{{ tab.label }}
-			</div>
-		</div>
-		<component :is="tabsComponents[tabActiveName]"></component>
-	</div>
+  <div class="asj-container">
+    <div class="public-search">
+      <TopFilter></TopFilter>
+      <el-select
+        v-model="selectedPortfolios"
+        placeholder="广告组合"
+        clearable
+        multiple
+        style="width: 200px"
+        collapse-tags
+        collapse-tags-tooltip
+        :max-collapse-tags="3"
+        disabled="true">
+        <el-option v-for="info of portfolios" :label="info.name" :value="info.portfolioId"></el-option>
+      </el-select>
+      <DateRangePicker v-model="dateRange"></DateRangePicker>
+    </div>
+    <div class="asj-tabs">
+      <div v-for="tab of tabs" :key="tab.name" :class="['asj-tab', { active: tabActiveName === tab.name }]" @click="tabActiveName = tab.name">
+        {{ tab.label }}
+      </div>
+    </div>
+    <component :is="tabsComponents[tabActiveName]"></component>
+  </div>
 </template>
 
 <style scoped>

+ 47 - 9
src/views/demo/index.vue

@@ -1,14 +1,52 @@
-<template>
-  <div style="width: 400px;">
-    <!-- <InfiniteScroll style="width: auto;"></InfiniteScroll> -->
-  </div>
+<script setup lang="ts">
+import { nextTick, ref } from 'vue'
 
-</template>
+const isVisible = ref(false)
 
-<script setup lang="ts">
-// import InfiniteScroll from '/@/views/productCenter/productAnalysis/components/InfiniteScroll/index.vue'
+function handleFocus() {
+  isVisible.value = true
+}
+
+function handleBlur() {
+  // 延时是为了解决点击Popover内容时,input失去焦点导致Popover立即关闭的问题。
+  setTimeout(() => {
+    isVisible.value = false
+  }, 200)
+}
 </script>
 
-<style scoped>
+<template>
+  <!-- <div style="max-width: 400px">
+    <el-popover :visible="isVisible" placement="bottom" title="Title" :width="200" content="this is content, this is content, this is content">
+      <template #reference>
+        <div>
+          <el-input v-model="input1" @click="handlePopover" style="width: 350px" placeholder="Please input">
+            <template #prepend>
+              <el-select v-model="select" placeholder="Select" style="width: 115px">
+                <el-option label="Restaurant" value="1" />
+                <el-option label="Order No." value="2" />
+                <el-option label="Tel" value="3" />
+              </el-select>
+            </template>
+          </el-input>
+        </div>
+      </template>
+    </el-popover>
+  </div> -->
+
+  <!-- <el-popover ref="popover" placement="right" title="Title" :width="200" trigger="focus" content="this is content, this is content, this is content">
+    <template #reference>
+      <el-button class="m-2">Focus to activate</el-button>
+    </template>
+  </el-popover> -->
+
+  <div>
+    <el-popover v-model:visible="isVisible" placement="bottom" title="Title" content="This is content">
+      <template #reference>
+        <el-input placeholder="Please input" @focus="handleFocus" @blur="handleBlur"></el-input>
+      </template>
+    </el-popover>
+  </div>
+</template>
 
-</style>
+<style scoped></style>