Commit ffc35a3f authored by zhengke's avatar zhengke

Merge branch '1.4.0'

parents 9e20cc1f 9053881b
......@@ -89,6 +89,21 @@ class ConfigService{
return Api.Post("triptemplate_RemoveTripOther",params)
}
/**
* 销售行程获取缓存数据
*/
static async GetTripOtherMongo(Id: any):Promise<HttpResponse>{
let params = {Id}
return Api.Post("triptemplate_GetTripOtherMongo",params)
}
/**
* 销售行程定时更新数据
*/
static async SetTripOtherTemp(params : any):Promise<HttpResponse>{
return Api.Post("triptemplate_SetTripOtherTemp",params)
}
/**
* 销售新增编辑模版
*/
......
import { array } from '@amcharts/amcharts4/core';
import Api,{ HttpResponse, Result } from './../utils/request';
class MatchingData{
static async ScenicSearch(params:any):Promise<HttpResponse>{
return Api.Post("mongoscenic_ScenicSearch",params)
}
}
export default MatchingData;
\ No newline at end of file
export const enum ToolbarStates {
SYMBOL = 'symbol',
EL_ANIMATION = 'elAnimation',
EL_NORMALDATA = 'normalData',
EDIT_DATAS = 'editDatas',
EL_TEMPLATEDATA = 'elTemplateData',
EL_STYLE = 'elStyle',
......
......@@ -35,7 +35,6 @@ export default (
})
newActiveIdList = [...newActiveIdList, ...groupMembersId]
}
mainStore.setActiveElementIdList(uniq(newActiveIdList))
mainStore.setHandleElementId(element.id)
}
......
......@@ -142,7 +142,7 @@
<script lang="ts" setup>
import { ArrowDown } from '@element-plus/icons-vue'
import { nextTick, ref, reactive, inject, computed, watch, provide } from 'vue'
import { nextTick, ref, reactive, inject, computed, watch, provide, onBeforeUnmount } from 'vue'
import { storeToRefs } from 'pinia'
import { toPng, toJpeg } from 'html-to-image'
import message from '@/utils/message'
......@@ -180,6 +180,7 @@ import { useRouter } from "vue-router";
import { managerTemplateLink, openNewBlank } from '@/utils/common'
const mainStore = useMainStore()
const { handleElement, handleElementId } = storeToRefs(mainStore)
const slidesStore = useSlidesStore()
const layoutsStore = useSlidesStore()
const { title, slides, slideIndex, viewportRatio } = storeToRefs(slidesStore)
......@@ -224,45 +225,80 @@ const journeyAdsDetails = ref<Object>()
const psdVisibleStatus = ref(false)
const { market, model, ConfigId, CoverImg, dataLoading, TempId, TempType, SourceLoading } = storeToRefs(useScreenStore())
const routers = useRouter();
if(queryObj.value.Title) titleValue.value = queryObj.value.Title
const MonitoringNumber = ref(0)
const MonitoringTNumber = ref(0)
const timer = 60
const Countdown = ref<any>(timer)
const intervalId = ref(null);
const showTimer = ref(false);
const goType = ref(null)
// 返回到首页 type 1 模版列表页 0 销售在线模版页
const goBack = (type:any) =>{
mainBackVisible.value = false
ElMessageBox.confirm(
'退出此页面将清空当前数据,请谨慎操作?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
setNewDatas(type,0)
mainStore.setToolbarState(ToolbarStates.SLIDE_DESIGN)
let path ='/'
const t = useSlidesStore().viewportRatio<0?1:2
searchData.value.SalesEditor = null
if(model.value==0) {
path = `/market/op/${ConfigId.value}/${TempType.value}`
router.push({path})
}else if(model.value==2){
if(type==1) {
searchData.value.SalesEditor = router.currentRoute.value.params
if(searchData.value.sellId)searchData.value.TempId2 = queryObj.value.TempId
marketStore.setMarket(true)
SalesBackStore.setSalesBack(1)
searchData.value.TempId = 0
if(searchData.value.sellId) path = `/market/create/${queryObj.value.TemplateType==1?'trip':'ad'}${searchData.value.currentMenu>=0?'/'+searchData.value.currentMenu:''}`
else path = `/market/create`
goType.value = type
if(model.value==2){
ElMessageBox.confirm(
'退出此页面将清空当前数据,是否保存当前数据,并退出?',
'提示',
{
confirmButtonText: '保存',
cancelButtonText: '退出',
type: 'warning',
}
else if(searchData.value.currentMenu>=0) {
path = `/space/${searchData.value.currentMenu}`
searchData.value.currentMenu = null
}else path = `/space`
router.push({path})
).then(() => {
if(searchData.value.sellId) {
clearInterval(intervalId.value);
intervalId.value = null;
}
setTemplate(0,1)
}).catch(() => {
SaveStroke(type)
})
}else{
ElMessageBox.confirm(
'退出此页面将清空当前数据,请谨慎操作?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
setNewDatas(type,0)
mainStore.setToolbarState(ToolbarStates.SLIDE_DESIGN)
let path ='/'
const t = useSlidesStore().viewportRatio<0?1:2
searchData.value.SalesEditor = null
if(model.value==0) {
path = `/market/op/${ConfigId.value}/${TempType.value}`
router.push({path})
}else window.history.back()
}).catch(() => {})
}
else window.history.back()
}).catch(() => {})
}
const SaveStroke = (type:any) => {
let path = ''
if(type==1) {
searchData.value.SalesEditor = router.currentRoute.value.params
if(searchData.value.sellId)searchData.value.TempId2 = queryObj.value.TempId
marketStore.setMarket(true)
SalesBackStore.setSalesBack(1)
searchData.value.TempId = 0
if(searchData.value.sellId) path = `/market/create/${queryObj.value.TemplateType==1?'trip':'ad'}${searchData.value.currentMenu>=0?'/'+searchData.value.currentMenu:''}`
else path = `/market/create`
}
else if(searchData.value.currentMenu>=0) {
path = `/space/${searchData.value.currentMenu}`
searchData.value.currentMenu = null
}else path = `/space`
router.push({path})
}
// 返回是否清空数据
const setNewDatas = (type,i) => {
......@@ -283,8 +319,40 @@ const UploadPsdHandler = () => {
psdVisibleStatus.value = true
}
// 倒计时更新数据
const benginTimer = () => {
showTimer.value = true;
intervalId.value = setInterval(() => {
if (Countdown.value === 0&&showTimer.value) {
clearInterval(intervalId.value);
intervalId.value = null;
showTimer.value = false
return UpdateItinerary()
} else if(Countdown.value>0) {
Countdown.value--;
}
}, 1000);
}
const UpdateItinerary = async () => {
if(datas.loading) return
queryObj.value.TempData = JSON.stringify(slides.value)
datas.loading = true
let queryMsg = {
Id: searchData.value.sellId,
Title: queryObj.value.Title,
TempId: queryObj.value.TempId,
TempData: queryObj.value.TempData,
}
const result = await ConfigService.SetTripOtherTemp(queryMsg);
if (result.data.resultCode == 1) {
console.log('更新行程数据成功-----')
}
datas.loading = false
}
// 销售新增修改行程、广告
const SetSellTemplate = async (type:Number,FolderId:Number) => {
const SetSellTemplate = async (type:Number,FolderId:Number,sellType:any) => {
if(FolderId>=0) datas.loading = true
try {
let TempId = 0
......@@ -327,7 +395,7 @@ const SetSellTemplate = async (type:Number,FolderId:Number) => {
SalesEditorStore.setSalesEditor(0)
},100)
if(autoSave.value==1)autoSave.value=2
if(type == 0 && Id==0){
if(type == 0 && Id==0 && !sellType){
let FileId = searchData.value.sellId=TemplateRes.data.data.Id
let FileType = TemplateRes.data.data.FileType?TemplateRes.data.data.FileType:0
//@TODO:返回字段中缺少CreateBy,
......@@ -336,6 +404,8 @@ const SetSellTemplate = async (type:Number,FolderId:Number) => {
path:url
})
}
// 保存并退出当前页
if(sellType) SaveStroke(goType.value)
}else{
ElMessage({
showClose: true,
......@@ -485,8 +555,8 @@ const SetTripTemplateConfig = async () => {
datas.loading = false
}
// 保存
const setTemplate = async (type) =>{
// 保存 type行程另存 sellType行程保存并退出
const setTemplate = async (type:any,sellType:any) =>{
queryObj.value.Title = title.value
if(SourceLoading.value) setNewDatasList(datas.DataSource)
......@@ -574,6 +644,8 @@ const setTemplate = async (type) =>{
datas.loading = true
await SetTripTemplateConfig()
}else if(model.value==2&&SalesEditor.value>0){
clearInterval(intervalId.value);
intervalId.value = null;
if(type==1||!searchData.value.sellId){
let obj = {
FileName: queryObj.value.Title,
......@@ -582,6 +654,7 @@ const setTemplate = async (type) =>{
}
journeyAdsDetails.value = obj
isCopyTo.value = true
if(sellType) await SetSellTemplate(type,0,sellType)
}else{
datas.loading = true
await SetSellTemplate(type)
......@@ -617,7 +690,35 @@ watch(()=>autoSave.value,(newVal)=>{
setTemplate(0)
}
})
watch(()=>slides.value,(newVal,oldVal)=>{
if(model.value==2&&SalesEditor.value>0&&searchData.value.sellId){
if(!MonitoringNumber.value||MonitoringNumber.value<2) MonitoringNumber.value++
if(MonitoringNumber.value>1) {
Countdown.value = timer
benginTimer()
}
}
},{
deep: true,
immediate: false
})
watch(()=>queryObj.value.Title,(newVal,oldVal)=>{
if(model.value==2&&SalesEditor.value>0&&searchData.value.sellId){
if(!MonitoringTNumber.value||MonitoringTNumber.value<2) MonitoringTNumber.value++
if(MonitoringTNumber.value>1) {
Countdown.value = timer
benginTimer()
}
}
})
handleUpdateTitle()
onBeforeUnmount(() => {
clearInterval(intervalId.value);
intervalId.value = null;
});
</script>
<style lang="scss" scoped>
......
......@@ -754,11 +754,56 @@ const sellGetTripTemplate = async () =>{
slidesStore.setSlides(newSlides)
}
}else ElMessage({
showClose: true,
message: dataRes.data.message,
type: 'warning',
})
if(searchData.value.sellId) getTripOtherMongo()
} catch (error) {
}
}
// 销售模版缓存数据
const getTripOtherMongo = async () =>{
return
try {
const loadingObj = ElLoading.service({text:'正在获取缓存数据',lock:true})
let dataRes = await ConfigService.GetTripOtherMongo(searchData.value.sellId);
if (dataRes.data.resultCode == 1) {
let dataObj = dataRes.data.data
let SlidesData = JSON.parse(dataObj.TempData)
let newSlides = []
SlidesData.forEach((x,i)=>{
x.elements.forEach((y:any)=>{
if(y.content && y.defaultFontName && y.defaultFontName.includes(',')) y.defaultFontName = y.defaultFontName.split(',')[0]
if(y.content && (y.content.includes('&amp;nbsp;'))){
y.content = y.content.replaceAll('&amp;nbsp;','&nbsp;')
//y.content=y.content.replaceAll('&nbsp;',' ')
}
if(y.contentStr && !y.contentStr.includes('<p') && y.content && y.content.includes(y.contentStr)){
let temp = HtmlUtil.htmlEncodeByRegExp(y.contentStr)
if(temp!=y.contentStr) {
y.content = y.content.replace(y.contentStr,temp)
}
}
})
newSlides.push(x)
})
slidesStore.setSlides(newSlides)
loadingObj.close()
}else {
loadingObj.close()
ElMessage({
showClose: true,
message: dataRes.data.message,
type: 'warning',
})
}
} catch (error) {
}
......
<template>
<div class="ElementNormalData">
<el-input
v-model="keywords" placeholder="输入关键词检索"
class="input-with-select q-pb-md" clearable
@input="SearchCloudInfo">
<template #prefix>
<IconSearch class="cusor-pointer" @click.stop="searchData"></IconSearch>
</template>
</el-input>
<div v-loading="loading" style="height: calc(100%-40px);min-height:400px;overflow: auto;">
<div class="symbol-item NormalDataCenter cursor-pointer"
:class="[current==item.Id?'active':'']"
v-for="(item,index) in dataList" @click="setElText(item,index)">
<div class="title fz14 text-weight-bold text-ellipsis">
<el-tooltip
style="width: 100%;"
effect="dark"
:content="item.Name"
placement="top"
>{{item.Name}}</el-tooltip>
</div>
<div class="images">
<el-image :src="item.PicPath" style="width: 100%;"
fit="cover">
<template #error>
<div class="row items-center" style="height: 100%;">
<el-image :src="errImg"></el-image>
</div>
</template>
</el-image>
</div>
<div class="text fz12">
<el-tooltip
style="width:200px;"
effect="dark"
:content="item.Feature"
placement="top"
>{{item.Feature}}</el-tooltip>
</div>
</div>
</div>
<div v-if="(!dataList || dataList.length==0) && !loading">
<el-empty class="q-ma-xl" description="暂无数据" />
</div>
</div>
<!-- 预览图 -->
<el-image-viewer
@close="() => { isViewerShow = false }"
v-if="isViewerShow"
:initial-index="currentImg"
:url-list="srcList"></el-image-viewer>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore, useScreenStore } from '@/store'
import MatchingData from '@/services/MatchingData'
import { getHtmlPlainText } from '@/utils/common'
import { useUserStore } from "@/store/user";
import HtmlUtil from '@/utils/htmlutil'
const { handleElement, handleElementId } = storeToRefs(useMainStore())
const errImg = ref(require('@/assets/img/noImg.png') as any)
const isViewerShow = ref(false)
const currentImg = ref(0)
const current = ref(null||Number)
const srcList = ref([])
const params = reactive({
kw: HtmlUtil.htmlEncodeByRegExp(handleElement.value.contentStr),
cn: '',
})
const keywords = ref('')
const slidesStore = useSlidesStore()
const dataList = ref([])
const dataListAll = ref([])
const loading = ref(true)
const { userInfo } = storeToRefs(useUserStore());
const SearchCloudInfo = () => {
if(keywords.value){
dataList.value = dataListAll.value.filter(x=>{
return x.Name.toLowerCase().includes(keywords.value.toLowerCase())
})
}else dataList.value = dataListAll.value
}
const seeImg = (index:Number) =>{
isViewerShow.value = true
currentImg.value = index
}
const setElText = (item:any,index:Number) => {
current.value = item.Id
const contentStr = handleElement.value.contentStr
if(contentStr!=item.Feature&&item.Feature) {
const content = handleElement.value.content.replace(getHtmlPlainText(handleElement.value.content),item.Feature)
const props = {
content,
contentStr:item.Feature
}
slidesStore.updateElement({
id: handleElementId.value,
props
})
}
}
const searchData = () => {
if(!keywords.value) return
params.kw = keywords.value
loading.value = true
getDatas()
}
const getDatas = async () => {
const response = await MatchingData.ScenicSearch(params)
if (response.data.resultCode == 1) {
dataListAll.value = dataList.value = checkPoiCoverImg(response.data.data)
}
loading.value = false
}
const checkPoiCoverImg = (array:any[])=>{
if(array.length==0) return
array.forEach((x,index)=>{
x.Id = index+1
if(x.Feature==handleElement.value.contentStr) current.value = index+1
if((!x.PicPath||x.PicPath=='') && x.ImgArray && x.ImgArray.length>0){
x.PicPath=x.ImgArray[0]
}else if(x.PicPath && x.PicPath!=''){
if(x.PicPath.indexOf('?')!=-1) x.PicPath=x.PicPath.split('?')[0]
x.ImgArray = x.ImgArray ?? []
x.ImgArray.splice(0,0,x.PicPath)
}
})
return array
}
getDatas()
watch(()=>handleElementId.value, () => {
loading.value = true
keywords.value = ''
params.kw = HtmlUtil.htmlEncodeByRegExp(handleElement.value.contentStr)
getDatas()
})
</script>
<style lang="scss" scoped>
.ElementNormalData{
height: 100%;
display: flex;
flex-direction: column;
}
.NormalDataCenter{
border: 2px solid #CED9FF;
padding: 8px 14px;
margin-bottom: 5px;
}
.NormalDataCenter.active{
border-color: #0B40FE;
}
.title{
font-family: PingFang SC;
}
.images{
width: 194px;
max-height: 139px;
overflow: hidden;
margin-top: 8px;
margin-bottom: 11px;
}
.text {
font-family: PingFang SC;
font-weight: 300;
color: #000;
line-height: 18px;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
</style>
\ No newline at end of file
......@@ -13,7 +13,7 @@
</template>
<script lang="ts" setup>
import { ref, computed, watch } from 'vue'
import { ref, computed, watch, inject } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store'
import { useScreenStore } from '@/store'
......@@ -23,11 +23,13 @@ import ElementStylePanel from './ElementStylePanel/index.vue'
import ElementPositionPanel from './ElementPositionPanel.vue'
import ElementAnimationPanel from './ElementAnimationPanel.vue'
import ElementTemplateData from './ElementTemplateData.vue'
import ElementNormalData from './ElementNormalData.vue'
import SlideDesignPanel from './SlideDesignPanel.vue'
import SlideAnimationPanel from './SlideAnimationPanel.vue'
import MultiPositionPanel from './MultiPositionPanel.vue'
import SymbolPanel from './SymbolPanel.vue'
import Tabs from '@/components/Tabs.vue'
import { injectKeyTemplate } from '@/types/injectKey'
interface ElementTabs {
label: string
......@@ -38,14 +40,28 @@ const mainStore = useMainStore()
const { activeElementIdList, handleElement, toolbarState } = storeToRefs(mainStore)
const { model } = storeToRefs(useScreenStore())
const searchData = ref({} as any)
searchData.value = inject(injectKeyTemplate)
const elementTabs = computed<ElementTabs[]>(() => {
if (handleElement.value?.type === 'text') {
return [
{ label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '符号', key: ToolbarStates.SYMBOL },
{ label: '位置', key: ToolbarStates.EL_POSITION },
// { label: '动画', key: ToolbarStates.EL_ANIMATION }
]
if(!searchData.value.isTeamManage){
return [
{ label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '符号', key: ToolbarStates.SYMBOL },
{ label: '位置', key: ToolbarStates.EL_POSITION },
// { label: '动画', key: ToolbarStates.EL_ANIMATION }
{ label: '匹配数据', key: ToolbarStates.EL_NORMALDATA }
]
}else{
return [
{ label: '样式', key: ToolbarStates.EL_STYLE },
{ label: '符号', key: ToolbarStates.SYMBOL },
{ label: '位置', key: ToolbarStates.EL_POSITION },
// { label: '动画', key: ToolbarStates.EL_ANIMATION }
]
}
}
return [
{ label: '样式', key: ToolbarStates.EL_STYLE },
......@@ -99,6 +115,7 @@ const currentPanelComponent = computed(() => {
[ToolbarStates.EL_TEMPLATEDATA]: ElementTemplateData,
[ToolbarStates.SLIDE_DESIGN]: SlideDesignPanel,
[ToolbarStates.SLIDE_ANIMATION]: SlideAnimationPanel,
[ToolbarStates.EL_NORMALDATA]: ElementNormalData,
[ToolbarStates.MULTI_POSITION]: MultiPositionPanel,
[ToolbarStates.SYMBOL]: SymbolPanel,
}
......
......@@ -67,7 +67,7 @@
</template>
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { computed, onMounted, onUnmounted, ref, watch, inject } from 'vue'
import { storeToRefs } from 'pinia'
import { debounce } from 'lodash'
import { useMainStore, useSlidesStore } from '@/store'
......@@ -78,6 +78,9 @@ import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import ElementOutline from '@/views/components/element/ElementOutline.vue'
import ProsemirrorEditor from '@/views/components/element/ProsemirrorEditor.vue'
import { ToolbarStates } from '@/types/toolbar'
import { injectKeyTemplate } from '@/types/injectKey'
const props = defineProps<{
elementInfo: PPTTextElement
......@@ -97,12 +100,15 @@ const editorRef = ref()
const shadow = computed(() => props.elementInfo.shadow)
const { shadowStyle } = useElementShadow(shadow)
const fullLockVisible = ref(0)
const searchData = ref({} as any)
searchData.value = inject(injectKeyTemplate)
const handleSelectElement = (e: MouseEvent | TouchEvent, canMove = true) => {
if(e.button && e.button== 1) return
if (props.elementInfo.lock) return
e.stopPropagation()
if(!searchData.value.isTeamManage) mainStore.setToolbarState(ToolbarStates.EL_NORMALDATA)
props.selectElement(e, props.elementInfo, canMove)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment