Commit 54fd6d73 authored by zhengke's avatar zhengke

Merge branch 'router' of http://gitlab.oytour.com/viitto/pptist into router

parents 84d3d42c fa4fcaa6
VUE_APP_API_URL = 'http://192.168.5.34/api/common/post'
VUE_APP_API_URL = 'http://192.168.5.87/api/common/post'
VUE_APP_UPLOADURLAPI_URL = 'http://192.168.10.214:8120'
VUE_APP_SHARE_URL = 'http://127.0.0.1:8080'
\ No newline at end of file
......@@ -12,6 +12,7 @@
"@amcharts/amcharts4": "^4.10.38",
"@amcharts/amcharts4-geodata": "^4.1.28",
"@element-plus/icons-vue": "^2.1.0",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
"@icon-park/vue-next": "^1.4.2",
"@types/ali-oss": "^6.16.11",
"@types/opentype.js": "^1.3.8",
......@@ -62,6 +63,7 @@
"vue": "^3.4.21",
"vue-konva": "^3.0.2",
"vue-router": "^4.0.13",
"vue-waypoint": "^4.3.0",
"vue3-leaderline": "^1.2.11",
"vuedraggable": "^4.1.0"
},
......
......@@ -31,6 +31,11 @@ page {
.absolute{
position: absolute;
}
.absolute.botton{
bottom: 0;
left: 0;
right: 0;
}
.alifont{
font-family: alifont,chineseAlifont;
}
......@@ -133,7 +138,7 @@ page {
color:#0b40fe;
}
.text-el-primary{
color: #d14424 !important;
color: #564bec !important;
}
.text-info{
color:#b1b7cf;
......@@ -437,11 +442,11 @@ page {
font-weight: bolder;
}
.rounded{
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
-ms-border-radius: 6px;
-o-border-radius: 6px;
border-radius: 8px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;
}
.relative{
position: relative;
......@@ -452,6 +457,12 @@ page {
.full-width{
width:100%;
}
.window-width{
width: 100vw;
}
.window-height{
height: 100vh;
}
.text-nategive{
color: #FF4B86;
}
......@@ -479,6 +490,9 @@ page {
.el-table__header .el-table .cell{
font-family: 'alifont';
}
.full-scroll .el-scrollbar__view{
height: 100% !important;
}
.el-button{
font-size: 12px !important;
}
......@@ -499,4 +513,35 @@ page {
width: 100%;
height: 1px;
background: #EDEDED;
}
.el-button--primary:not(.is-link),
.theme-item .btn{
background: linear-gradient(134deg, #649DED, #570AD8) !important;
border: none !important;
}
.text-dark{
color:#1F2429;
}
.el-button--primary:not(.is-link):hover,
.theme-item .btn:hover{
background: linear-gradient(134deg, #649DEDef, #550ad8ef) !important;
}
.el-button:not(.is-link):hover,
.el-menu-item:hover{
background-color: #564bec22 !important;
border-color: #564bec !important;
}
.el-button.is-link:focus,
.el-button.is-link:hover{
color: #564becCC !important;
}
.full-dialog{
background-color: rgba(0,0,0,0.4);
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9;
}
\ No newline at end of file
......@@ -136,8 +136,8 @@ textarea {
background-color: #c1c1c1;
}
:root {
--el-color-primary: #d14424 !important;
--el-color-primary-light-3: #de6949 !important;
--el-color-primary: #564bec !important;
--el-color-primary-light-3: #564bec !important;
--el-color-primary-light-5: #e68d79 !important;
--el-color-primary-light-7: #f8a491 !important;
--el-color-primary-light-8: #fdcec4 !important;
......
$themeColor: #d14424;
$themeHoverColor: #de6949;
$themeColor: #564bec;
$themeHoverColor: #564becde;
$textColor: #41464b;
$borderColor: #eee;
$lightGray: #f9f9f9;
......@@ -10,4 +10,6 @@ $transitionDelay: .2s;
$transitionDelayFast: .1s;
$transitionDelaySlow: .3s;
$borderRadius: 2px;
\ No newline at end of file
$borderRadius: 2px;
$el-color-primary:#564bec;
\ No newline at end of file
<template>
<div class="full-dialog column flex-center items-center">
<div class="q-pa-lg bg-white rounded light-shadow" style="width:600px;">
<div class="text-weight-bold q-mb-lg" style="font-size: 18px;">微信支付</div>
<div class="text-center">
<div class="row flex-center">
<QRCode value="https://www.baidu.com" :size="200"></QRCode>
<img src="https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713233895000_458.jpg" class="q-ml-md" style="height:200px;">
</div>
<div class="text-body2 q-mt-lg text-grey-6">请打开微信(WeChat),使用 [扫一扫]扫描上方二维码进行支付</div>
<div class="q-mt-xl text-right">
<el-button class="q-px-md q-mr-md">取消支付</el-button>
<el-button type="primary" class="q-px-md" >已完成付款</el-button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import QRCode from '../QRCode/QRCode.vue';
</script>
<style>
</style>
\ No newline at end of file
<template>
<el-popover :width="300" popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;" >
<template #reference>
<div class="row items-center cursor-pointer">
<el-avatar :size="40" :src="userInfo.photo" v-if="userInfo.photo && userInfo.photo.includes('http')"></el-avatar>
<el-avatar :size="40" v-else class="bg-primary text-white">{{ userInfo.nickname[0] }}</el-avatar>
<div class="q-ml-md">
<div class="" style="font-size: 16px; line-height: 1">{{ userInfo.nickname }}</div>
<img :src="vipIcon" style="height: 15px;"/>
</div>
</div>
</template>
<template #default>
<div class="row items-center text-small" >
<span class="text-grey-8">个人账号ID:</span>
<span class="col text-info" >1572131810</span>
<el-button class="text-grey-8" link>退出登录</el-button>
</div>
</template>
</el-popover>
<div class="items-center row">
<el-dropdown trigger="click">
<el-avatar
:size="40"
:src="userInfo.photo"
style="background-color: #e6ddf5; color: #7b35ef"
class="q-mx-lg cusor-pointer"
>{{
userInfo.photo && userInfo.photo.includes("http")
? ""
: userInfo.nickname[0]
}}</el-avatar
>
<template #dropdown>
<div class="MarketfigurePopover shrink">
<div class="row">
<!-- <div class="MarketfigureMin pointer shrink">
<img class="reactive" src="../../assets/img/figure.png" />
</div> -->
<el-avatar
:size="40"
:src="userInfo.photo"
style="background-color: #e6ddf5; color: #7b35ef"
class="q-mr-lg cusor-pointer shrink"
>{{
userInfo.photo && userInfo.photo.includes("http")
? ""
: userInfo.nickname[0]
}}</el-avatar
>
<div>
<div class="row items-center MarketfigureName">
<span>{{ userInfo.nickname }}</span>
<img
src="../../assets/img/homeVip1.png"
width="65"
height="16"
/>
</div>
<div class="row MarketfigurePhon">
<span>ID:123453789</span>
<span>电话:180****1613</span>
</div>
</div>
</div>
<div class="MarketEquity">
<div class="MarketEquityNum">
<span>功能权益</span>
<span>5+</span>
</div>
<div class="MarketEquityTime">有效期至2024.07.03</div>
</div>
<div class="MarketCapacity">
<div>
<el-progress
:percentage="100"
color="#0A5EF9"
:stroke-width="8"
text-inside
:format="format"
>
</el-progress>
</div>
<div class="MarketCapacityNum row flex-between">
<span>7.88 GB / 1.34 TB</span>
<span>容量管理</span>
</div>
</div>
<div class="MarketFootmark row items-center flex-between">
<div>
<span>足迹</span>
<b>10</b>
</div>
<div>
<span>收藏</span>
<b>10</b>
</div>
<div>
<span>共享</span>
<b>10</b>
</div>
</div>
<div class="TranLine"></div>
<div class="MarketSettings row flex-between">
<span>账号设置</span>
<span class="pointer" @click="loginOutHandler">退出登录</span>
</div>
</div>
</template>
</el-dropdown>
<el-dropdown trigger="click">
<el-icon class="pointer" size="21" color="#070707"
><MoreFilled
/></el-icon>
<template #dropdown>
<div class="MarketPopoverMore row wrap pointer">
<div class="column" v-for="(item, index) in moreList">
<div>
<img :src="item.icon" width="34" height="34" />
</div>
<span>{{ item.Name }}</span>
</div>
</div>
</template>
</el-dropdown>
</div>
</template>
<script lang="ts" setup>
import { useUserStore } from '@/store'
import { storeToRefs } from 'pinia'
import { useUserStore } from "@/store";
import { storeToRefs } from "pinia";
const useUser = useUserStore()
const {userInfo} = storeToRefs(useUser)
const vipIcon = 'https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1712478244000_568.png'
const useUser = useUserStore();
const { userInfo } = storeToRefs(useUser);
const moreList = [
{ icon: require("@/assets/img/homeMore0.png"), Name: "添加到桌面" },
{ icon: require("@/assets/img/homeMore1.png"), Name: "关注公众号" },
{ icon: require("@/assets/img/homeMore2.png"), Name: "我的订单" },
{ icon: require("@/assets/img/homeMore3.png"), Name: "意见反馈" },
];
const loginOutHandler = ()=>{
useUser.setUserLoginOut()
}
</script>
<style scoped>
.MarketfigureName {
font-family: PingFang SC;
font-weight: bold;
font-size: 18px;
color: #000000;
margin-top: 3px;
}
.MarketfigureMin img {
margin-top: 18px;
}
.MarketCapacityNum span:last-child {
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #5f68e5;
}
.MarketCapacityNum span:first-child {
font-family: PingFang SC;
font-weight: bold;
font-size: 14px;
color: #4e4e4e;
}
.MarketCapacityNum {
margin-top: 10px;
}
.MarketfigurePhon span:last-child {
margin-left: 20px;
}
.MarketfigurePhon {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #b4b4b4;
margin-top: 5px;
}
.MarketfigureMin {
background: #e6ddf5;
width: 52px;
height: 52px;
border-radius: 50%;
text-align: center;
margin-right: 10px;
overflow: hidden;
}
.MarketfigurePopover {
width: 380px;
padding: 24px 30px 0 30px;
}
/* .Marketfigure:hover img {
animation: myfirst 1s;
-webkit-animation: myfirst 1s;
} */
.Marketfigure img {
margin-top: 6px;
}
/* @keyframes myfirst {
from {
margin-top: 25px;
}
to {
margin-top: 6px;
}
}
</style>
\ No newline at end of file
@-webkit-keyframes myfirst {
from {
margin-top: 25px;
}
to {
margin-top: 6px;
}
} */
.Marketfigure {
background: #e6ddf5;
width: 40px;
height: 40px;
border-radius: 50%;
text-align: center;
margin-left: 30px;
margin-right: 22px;
overflow: hidden;
}
.MarketPopoverMore > div span {
text-align: right;
padding-right: 17px;
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #000000;
}
.MarketPopoverMore > div div {
padding: 20px 0 22px 20px;
}
.MarketPopoverMore > div:first-child,
.MarketPopoverMore > div:nth-child(2) {
margin-bottom: 25px;
}
.MarketPopoverMore > div:nth-child(2n) {
margin-left: 28px;
}
.MarketPopoverMore > div {
width: 140px;
height: 105px;
border-radius: 8px;
background: #f3f6fb;
}
.MarketPopoverMore {
width: 368px;
padding: 30px;
}
.MarketEquityTime {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #8aa3cc;
}
.MarketEquityNum span:last-child {
margin-left: 12px;
}
.MarketEquityNum {
height: 14px;
font-family: PingFang SC;
font-weight: bold;
font-size: 14px;
color: #000000;
margin-bottom: 12px;
}
.MarketEquity {
height: 68px;
background: url("../../assets/img/home-quanyi.png") no-repeat;
background-size: 100% 100%;
padding: 18px 13px;
margin-top: 29px;
margin-bottom: 30px;
}
.MarketFootmark b {
color: #0a5ef9;
margin-left: 5px;
}
.MarketFootmark span {
font-size: 14px;
color: #000000;
font-family: PingFang SC;
}
.MarketFootmark {
width: 100%;
padding: 18px 21px;
background: #eee;
border-radius: 8px;
margin-top: 28px;
margin-bottom: 39px;
}
.MarketSettings span:last-child {
font-weight: 400;
color: #b4b4b4;
}
.MarketSettings span:first-child {
font-weight: 500;
color: #000000;
padding: 10px 0 20px 0;
}
.MarketSettings span {
font-family: PingFang SC;
font-size: 14px;
padding: 10px 0 20px 20px;
}
.MarketSettings {
margin-top: 9px;
}
</style>
......@@ -12,6 +12,11 @@ export enum ApiResult{
'TOKEN_INVALID' = 10000,
'TOKEN_ILLEGAL' = 10001,
}
export enum VipType{
'TEAM' = 2,
'PERSON' = 1
}
/**
* get status code
* @param {AxiosResponse} response Axios response object
......
......@@ -9,7 +9,7 @@ const router = createRouter({
})
const whiteList = ['/autoLogin','/login','/notfound']
const whiteList = ['/autoLogin','/login','/notfound','/regist']
const managerMenu = ['/market','/editor_admin']
let loadingInstance:any = null
......@@ -25,6 +25,9 @@ router.beforeEach((to:any, from:any, next:any) => {
if(managerMenu.includes(to.path) && user.getUser.isTemplate!=1){
next('/notfound');
}
if(to.path.includes('/regist') && user.getUserToken!=''){
next('/login');
}
if (to.meta.title) {
document.title = to.meta.title
}
......
......@@ -4,10 +4,40 @@ import { RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('@/views/Website/index.vue'),
meta:{
title:'Travel Design 一个面向旅游行程设计的创作平台'
}
},
{
path: '/space',
component: () => import('@/views/Index.vue'),
meta:{
title:'个人空间'
}
},
children:[
{
path: '/space',
component: () => import('@/views/SellTemplate/Workspace.vue'),
meta:{
title:'个人空间'
}
},
{
path: '/space/:current(\\d+)?',
component: () => import('@/views/SellTemplate/Workspace.vue'),
meta:{
title:'个人空间'
}
},
{
path: '/space/cp',
component: () => import('@/views/Company/Product.vue'),
meta:{
title:'升级到企业版本'
}
}
]
},
{
path: '/login',
......@@ -16,6 +46,13 @@ const routes: RouteRecordRaw[] = [
title:'登录 Travel Design'
}
},
{
path: '/regist',
component: () => import('@/views/Auth/Regist.vue'),
meta:{
title:'注册 Travel Design'
}
},
{
path: '/notfound',
component: () => import('@/views/ErrorNotFound.vue'),
......@@ -127,6 +164,13 @@ const routes: RouteRecordRaw[] = [
meta:{
title:'行程生成预览'
}
},
{
path: '/:catchAll(.*)*',
component: () => import('@/views/ErrorNotFound.vue'),
meta:{
title:'Oops! 出错了'
}
}
];
......
import Api,{ HttpResponse, Result } from './../utils/request';
class OrderService{
static async CreateOrderAsync(parameters:any):Promise<HttpResponse>{
let msg = parameters
return Api.Post("ppt_SetPPTOrder",msg)
}
static async GetOrders():Promise<HttpResponse>{
let msg = {Status: 0, is_show: 0, RB_Group_Id: 2}
return Api.Post("admin_get_BranchGetList",msg)
}
}
export default OrderService;
\ No newline at end of file
......@@ -12,5 +12,16 @@ class UserServices{
let msg = {account,pwd,tid}
return Api.Post("travel_login_password",msg)
}
static async RegistUserByPassAsync(account:string,pwd:string,nickname:string,token:string,tid:string=''):Promise<HttpResponse>{
let msg:any = {account,pwd,nickname,"v_token":token}
if(tid!='') msg.tid = tid
return Api.Post("travel_user_regist_pwd",msg)
}
static async GetProductAsync():Promise<HttpResponse>{
let msg = {pageIndex:1,pageSize:100}
return Api.Post("ppt_GetPPTProduct",msg)
}
}
export default UserServices;
\ No newline at end of file
......@@ -4,7 +4,8 @@ export interface SalesState {
SalesEditor: number,
SalesBack: number,
SalesTripId: string,
SaleHashCode: string
SaleHashCode: string,
SaleSearchPosition: any
}
export const useSellTemplateStore = defineStore('sales', {
......@@ -12,9 +13,14 @@ export const useSellTemplateStore = defineStore('sales', {
SalesEditor: 0, // 1 新增模版 2编辑模版 3新增广告 4编辑广告
SalesBack: 0,// 0 销售首页 1 模版首页
SalesTripId: '', // 销售行程id
SaleHashCode:''
SaleHashCode:'',
SaleSearchPosition: null
}),
getters: {
getSearchPosition (state) {
return state.SaleSearchPosition
}
},
actions: {
setSalesEditor(SalesEditor: number) {
this.SalesEditor = SalesEditor
......@@ -27,6 +33,9 @@ export const useSellTemplateStore = defineStore('sales', {
},
setSaleHashCode(hash:string){
this.SaleHashCode = hash
},
setSaleSearchPosition(value: any){
this.SaleSearchPosition = value
}
},
})
\ No newline at end of file
......@@ -47,6 +47,8 @@ export const useUserStore = defineStore('user', {
d.company = d.GroupName
d.logo = d.GroupPic
d.isTemplate = d.IsEditTripTemplate
d.ia = 0
d.it = true
this.userInfo = d
return true
......
......@@ -15,7 +15,10 @@ export const openNewBlank = (path:string) => {
window.open(url, '_blank')
}
}
export const openCustomerService = ()=>{
const url = 'https://work.weixin.qq.com/kfid/kfc378aada578ca8b0e'
window.open(url, '_blank')
}
export const createSaleEditorLink = (id:number,tid:number,type:1|2,pid:number,ep:0|1,cp:0|1) =>{
return `/editor/${id}/${tid}/${type}/${pid}/e/${ep}/c/${cp}`
}
......
......@@ -43,7 +43,7 @@
</el-form-item>
<div class="text-info text-small row flex-center">
<span>还没有账号?</span>
<el-button link type="primary" class="q-mb-lg">立即注册</el-button>
<el-button link type="primary" class="q-mb-lg" @click="redicetToRegist">立即注册</el-button>
</div>
</el-form>
</template>
......@@ -133,7 +133,7 @@ const userLoginHandler = async ()=>{
const result = await user.setUserPasswordLoginAsync(model.value.account,model.value.password,model.value.tid)
if(result.status=='SUCCESS'){
ElMessage.success({message:'登录成功'})
location.href='/';
location.href='/space';
}else if(result.status=='CHOSEN' && Array.isArray(result.data)){
multipleUsers.value = result.data
}else{
......@@ -142,9 +142,11 @@ const userLoginHandler = async ()=>{
}
const forwardWorkspaceHandler = ()=>{
location.href='/';
location.href='/space';
}
const redicetToRegist = ()=>{
location.href='/regist'
}
const clearCompanyChoosenHandler = ()=>{
multipleUsers.value=[]
model.value.tid=''
......
<template>
<div class="window-height regist-box column flex-center items-center">
<div class="col column flex-center items-center rounded light-shadow q-pa-xl bg-white" style="margin: 60px 0;">
<div style="width:400px;">
<div class="text-center">
<div style="font-size: 36px; " class="text-dark">创建Travel Design账户</div>
<div class="text-info text-small">开启行程设计第一步</div>
</div>
<el-form ref="registFormRef" :model="model" :rules="rules" label-width="0px" size="large" class="full-width q-mt-lg" :disabled="loading">
<el-form-item label="" prop="nickname">
<el-input v-model="model.nickname" placeholder="昵称" class="q-mt-lg" />
</el-form-item>
<el-form-item label="" prop="account">
<el-input v-model="model.account" placeholder="账号" />
</el-form-item>
<el-form-item label="" prop="password">
<el-input v-model="model.password" type="password" placeholder="设置密码" autocomplete="new-password" show-password/>
</el-form-item>
<el-form-item label="" prop="confirmPwd">
<el-input v-model="model.confirmPwd" type="password" placeholder="确认密码" autocomplete="new-password" show-password/>
</el-form-item>
<el-form-item label="">
<vue-hcaptcha ref="invisibleHcaptcha" sitekey="46e00e53-ddb2-4e7b-9c51-621534c2f1f5" @verify="verifyHandler"></vue-hcaptcha>
</el-form-item>
<el-form-item>
<el-button type="primary" class="full-width q-mb-lg" @click="submitForm(registFormRef)" :loading="loading">立即注册</el-button>
</el-form-item>
<div class="text-info text-small row flex-center">
<span>已有账号?</span>
<el-button link type="primary" class="q-mb-lg" @click="redicetToLogin">立即登录</el-button>
</div>
</el-form>
</div>
</div>
<div class="text-small text-info q-mb-lg">@2012-2024 成都微途科技有限公司 版权所有 蜀ICP备13024891号-9</div>
</div>
</template>
<script lang="ts" setup>
import { ElMessage, FormInstance, FormRules } from 'element-plus';
import { reactive, ref } from 'vue';
import UserServices from '@/services/UserService'
import { ApiResult } from '@/configs/axios';
import VueHcaptcha from "@hcaptcha/vue3-hcaptcha";
interface RuleForm {
account: string
password: string
nickname: string
confirmPwd:string
}
const model = ref<{account:string,password:string,nickname:string,confirmPwd:string}>({
account:'luochao',
password:'123456',
nickname:'罗超',
confirmPwd:'123456'
})
const validateToken = ref('')
const registFormRef = ref<FormInstance>()
const invisibleHcaptcha = ref<VueHcaptcha|null>(null)
const loading = ref(false)
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('请再次确认密码'))
} else if (value != model.value.password) {
callback(new Error("两次输入的密码不一致"))
} else {
callback()
}
}
const rules = reactive<FormRules<RuleForm>>({
account: [
{ required: true, message: '请输入你的账号', trigger: 'blur' },
{ min: 6, message: '账号至少是6位', trigger: 'blur' },
{ max: 16, message: '账号最长只能是16位', trigger: 'blur' },
],
nickname: [
{ required: true, message: '请输入你的昵称', trigger: 'blur' },
{ max: 8, message: '昵称最长只能是8位', trigger: 'blur' },
],
password: [
{ required: true, message: '请输入你的密码', trigger: 'blur' },
{ min: 6,max:20, message: '密码的长度应为6-20位', trigger: 'blur' },
],
confirmPwd:[
{ validator: validateConfirmPassword, trigger: 'blur' }
]
})
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate(async (valid) => {
loading.value=true
if (valid) {
if (invisibleHcaptcha.value && validateToken.value == '') {
invisibleHcaptcha.value.execute()
loading.value=false
return
}
await registHandler()
}
loading.value=false
})
}
const registHandler = async () =>{
const response = await UserServices.RegistUserByPassAsync(model.value.account,model.value.password,model.value.nickname,validateToken.value)
if(response.data.resultCode == ApiResult.SUCCESS){
ElMessage.success({message:'注册成功,正在跳转'})
setTimeout(() => {
redicetToLogin()
}, 1000);
return
}
ElMessage.error({message:response.data.message})
invisibleHcaptcha.value?.reset()
validateToken.value=''
}
const verifyHandler = (token:string,ekey:string)=>{
validateToken.value = token
}
const redicetToLogin = ()=>{
location.href='/login'
}
</script>
<style>
.regist-box{
background-image: url('../../assets/img/homeBJ.png'),linear-gradient(0deg, #E3ECFF, #FFFFFF);
background-size: auto auto;
background-repeat: no-repeat;
}
</style>
\ No newline at end of file
<template>
<div class="full-width relative">
<el-scrollbar class="q-pa-md full-width full-height full-scroll" style="padding-bottom: 96px;">
<div class="column flex-center items-center" style="min-height: 100%;">
<div class="text-weight-bold" style="font-size: 36px">
全新Travel Design一站式协同行程设计平台
</div>
<div style="font-size: 24px" class="q-mt-md">
开启企业版会员,全组织,多场景协同
</div>
<div class="q-py-lg row q-mt-xl" v-loding="loading">
<div
class="q-mr-lg rounded bg-white light-shadow q-pa-lg product-item cusor-pointer"
:class="{ active: choosenVersion && x.priceid == choosenVersion.priceid }"
v-for="(x, i) in products"
@click="choosenVersionHandler(x)"
>
<div style="font-size: 20px" class="text-center">
{{ x.vipname }}
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">可用人数</div>
<div class="text-dark">
{{ x.maxuser != 0 ? x.maxuser : "定制" }}
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">云盘空间</div>
<div class="text-dark">{{ space[i] }}</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">预制POI信息</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">PDF与图片输出</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">所有模板通用</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">组织内部共享行程</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">上传自定义模板</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">急速创建行程</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">AI报价工具</div>
<div class="text-dark">
<img src="../../assets/img/gou.png" style="width: 15px" />
</div>
</div>
<div class="row items-center text-info q-mt-lg">
<div class="col">价格</div>
<div class="text-dark" v-if="x.disprice > 0">
<span style="font-size: 20px">{{ x.disprice.toFixed(2) }}</span>
/年
</div>
<div class="text-dark" v-else>面议</div>
</div>
</div>
</div>
</div>
</el-scrollbar>
<div class="absolute botton light-shadow rounded q-pa-lg bg-white row items-center">
<div class="text-info text-small col" >
当前选中产品:
<span class="text-dark">{{ choosenVersion?choosenVersion.vipname:'未选择企业产品' }}</span>
</div>
<div class="text-info text-small" v-if="choosenVersion && choosenVersion.disprice>0">价格信息:</div>
<div v-if="choosenVersion && choosenVersion.disprice>0">
<span style="font-size: 24px">{{ choosenVersion.disprice.toFixed(2) }}</span>
/年
</div>
<div class="q-ml-lg">
<el-button type="primary" v-if="choosenVersion" :loading="creating" @click="createOrderHandler">{{ choosenVersion.disprice > 0?'确认购买':'联系客服' }}</el-button>
</div>
</div>
</div>
<WePay v-if="showPay"></WePay>
</template>
<script lang="ts" setup>
import { ApiResult, VipType } from "@/configs/axios";
import UserServices from "@/services/UserService";
import OrderService from '@/services/OrderService'
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { openCustomerService } from "@/utils/common";
import WePay from '@/components/Pay/WePay.vue'
const loading = ref(false);
const products = ref<any[]>();
const space = ref<string[]>(["20G", "100G", "定制"]);
const choosenVersion = ref<any>(null);
const creating = ref(false)
const showPay = ref(true)
const formatProductHandler = (data: any[]) => {
if (Array.isArray(data)) {
products.value = data.filter((x) => x.viptype == VipType.TEAM);
console.log(products.value);
}
};
const getProduct = async () => {
loading.value = true;
const response = await UserServices.GetProductAsync();
if (response.data.resultCode == ApiResult.SUCCESS) {
formatProductHandler(response.data.data.pageData);
}
loading.value = false;
}
const choosenVersionHandler = (item:any)=>{
choosenVersion.value = item
}
const createOrderHandler = async ()=>{
if(choosenVersion.value && !creating.value){
if(choosenVersion.value.disprice>0){
creating.value=true
const parameters = {
priceid:choosenVersion.value.priceid,
vipid:choosenVersion.value.vipid,
pricetype:1,
price:choosenVersion.value.disprice,
activedate:'2024-04-15',
orderid:0
}
const response = await OrderService.CreateOrderAsync(parameters)
if(response.data.resultCode == ApiResult.SUCCESS){
ElMessage.success({message:'订单创建成功,正在调起支付'})
creating.value = false
return
}
ElMessage.error({message:response.data.message})
creating.value = false
}else{
openCustomerService()
}
}
}
getProduct();
</script>
<style scoped>
.product-item {
width: 255px;
}
.product-item:hover,
.product-item.active {
background: linear-gradient(134deg, #649ded, #570ad8);
color: #fff !important;
}
.product-item:hover .text-info,
.product-item.active .text-info {
color: #efefef;
}
.product-item:hover .text-dark,
.product-item.active .text-dark {
color: #fff;
}
.product-item:hover img,
.product-item.active img {
filter: grayscale(100%) brightness(200%);
}
.absolute.botton{
bottom: 20px;
right: 20px;
left: 20px;
}
</style>
......@@ -16,7 +16,7 @@
>
<path
:d="lineData.path"
stroke="#d14424"
stroke="#564bec"
fill="none"
stroke-width="2"
></path>
......
......@@ -9,7 +9,7 @@
<svg overflow="visible">
<path
:d="path"
stroke="#d14424"
stroke="#564bec"
:fill="closed ? 'rgba(226, 83, 77, 0.15)' : 'none'"
stroke-width="2"
></path>
......
<template>
<div style="height: 100vh;background: rgb(243, 246, 251);">
<Workspace />
<div style="height: 100vh; background: rgb(243, 246, 251)">
<div class="workspace column">
<div class="row q-pa-md items-center" style="padding-bottom: 15px">
<img
src="https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1708239425000_437.png"
style="height: 30px"
/>
<div class="col text-center">
<SearchDocument @open-position="openFilePosition"></SearchDocument>
</div>
<div class="user">
<UserCard></UserCard>
</div>
</div>
<div class="col row">
<div class="q-ml-md full-height column">
<div class="col">
<el-tooltip effect="dark" content="我的设计空间" placement="right">
<div class="left-button" @click="redicetTo('/space')" :class="{'active':isWorkspace}">
<span class="svg-icon svg-icon-primary svg-icon-2x">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24px"
height="24px"
viewBox="0 0 24 24"
version="1.1"
>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<rect x="0" y="0" width="24" height="24" />
<path
d="M12.7037037,14 L15.6666667,10 L13.4444444,10 L13.4444444,6 L9,12 L11.2222222,12 L11.2222222,14 L6,14 C5.44771525,14 5,13.5522847 5,13 L5,3 C5,2.44771525 5.44771525,2 6,2 L18,2 C18.5522847,2 19,2.44771525 19,3 L19,13 C19,13.5522847 18.5522847,14 18,14 L12.7037037,14 Z"
fill="#0b40fe"
opacity="0.3"
/>
<path
d="M9.80428954,10.9142091 L9,12 L11.2222222,12 L11.2222222,16 L15.6666667,10 L15.4615385,10 L20.2072547,6.57253826 C20.4311176,6.4108595 20.7436609,6.46126971 20.9053396,6.68513259 C20.9668779,6.77033951 21,6.87277228 21,6.97787787 L21,17 C21,18.1045695 20.1045695,19 19,19 L5,19 C3.8954305,19 3,18.1045695 3,17 L3,6.97787787 C3,6.70173549 3.22385763,6.47787787 3.5,6.47787787 C3.60510559,6.47787787 3.70753836,6.51099993 3.79274528,6.57253826 L9.80428954,10.9142091 Z"
fill="#0b40fe"
/>
</g>
</svg>
</span>
</div>
</el-tooltip>
<el-tooltip effect="dark" content="模板广场" placement="right">
<div class="left-button q-mt-md" @click="openMarketHandler()">
<span class="svg-icon svg-icon-primary svg-icon-2x">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24px"
height="24px"
viewBox="0 0 24 24"
version="1.1"
>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<polygon points="0 0 24 0 24 24 0 24" />
<circle
fill="#564bec"
opacity="0.3"
cx="15"
cy="17"
r="5"
/>
<circle
fill="#564bec"
opacity="0.3"
cx="9"
cy="17"
r="5"
/>
<circle
fill="#564bec"
opacity="0.3"
cx="7"
cy="11"
r="5"
/>
<circle
fill="#564bec"
opacity="0.3"
cx="17"
cy="11"
r="5"
/>
<circle
fill="#564bec"
opacity="0.3"
cx="12"
cy="7"
r="5"
/>
</g>
</svg>
</span>
</div>
</el-tooltip>
</div>
<el-popover placement="right" trigger="click" width="320">
<template #reference>
<div class="left-button q-mb-md" :class="{'active':!isWorkspace}" title="企业中心">
<span class="svg-icon svg-icon-primary svg-icon-2x">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24px"
height="24px"
viewBox="0 0 24 24"
version="1.1"
>
<g
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<rect x="0" y="0" width="24" height="24" />
<path
d="M12.7442084,3.27882877 L19.2473374,6.9949025 C19.7146999,7.26196679 20.003129,7.75898194 20.003129,8.29726722 L20.003129,15.7027328 C20.003129,16.2410181 19.7146999,16.7380332 19.2473374,17.0050975 L12.7442084,20.7211712 C12.2830594,20.9846849 11.7169406,20.9846849 11.2557916,20.7211712 L4.75266256,17.0050975 C4.28530007,16.7380332 3.99687097,16.2410181 3.99687097,15.7027328 L3.99687097,8.29726722 C3.99687097,7.75898194 4.28530007,7.26196679 4.75266256,6.9949025 L11.2557916,3.27882877 C11.7169406,3.01531506 12.2830594,3.01531506 12.7442084,3.27882877 Z M12,14.5 C13.3807119,14.5 14.5,13.3807119 14.5,12 C14.5,10.6192881 13.3807119,9.5 12,9.5 C10.6192881,9.5 9.5,10.6192881 9.5,12 C9.5,13.3807119 10.6192881,14.5 12,14.5 Z"
fill="#564bec"
/>
</g>
</svg>
</span>
</div>
</template>
<div class="q-pa-md rounded">
<template v-if="!userInfo.it">
<div class="row items-center">
<div class="text-info text-small col">未加入任何企业</div>
<el-button type="primary" @click="redicetTo('/cp')" link icon="officeBuilding">立即创建企业</el-button>
</div>
<el-divider />
<el-menu mode="vertical">
<el-menu-item index="1">
<el-icon><Plus /></el-icon>
<span>加入企业</span>
</el-menu-item>
<el-menu-item index="2">
<el-icon><Setting /></el-icon>
<span>设置</span>
</el-menu-item>
</el-menu>
</template>
</div>
</el-popover>
</div>
<div class="q-mx-md col bg-white right-box row">
<router-view />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import Workspace from './SellTemplate/Workspace.vue';
</script>
<style lang="scss">
</style>
\ No newline at end of file
</div>
</template>
<script lang="ts" setup>
import { useUserStore } from "@/store/user";
import { storeToRefs } from "pinia";
import SearchDocument from "@/views/SellTemplate/components/SearchDocument.vue";
import UserCard from "@/components/User/UserCard.vue";
import { Plus, Setting } from "@element-plus/icons-vue";
import { openNewBlank } from "@/utils/common";
import { useSellTemplateStore } from "@/store";
import { useRouter } from "vue-router";
import { ref } from "vue";
const { userInfo } = storeToRefs(useUserStore());
const sellStore = useSellTemplateStore()
const router = useRouter()
const isWorkspace = ref(true)
isWorkspace.value = !router.currentRoute.value.path.includes('/cp')
const openMarketHandler = (type: string = "") => {
openNewBlank(`/market/create${type}`);
};
const openFilePosition = (playload:any)=>{
sellStore.setSaleSearchPosition(playload)
let currentMenu = 0
if(!playload.FormShare){
currentMenu = playload.FileType==1?3:4
}
else currentMenu = 2
router.push({
path:"/"+currentMenu
})
}
const redicetTo = (path:string)=>{
isWorkspace.value = !path.includes('/cp')
router.push({
path
})
}
</script>
<style>
.workspace{
width: 100vw;
height: 100vh;
background: #e7edf1;
}
.left-button{
width: 50px;
height: 50px;
padding: 14px;
border-radius: 8px;
cursor: pointer;
}
.left-button:hover{
background: rgba(0,0,0,.05);
}
.left-button.active{
background: #FFF !important;
}
.right-box{
border:1px solid #ddd;
border-top-right-radius: 8px;
border-top-left-radius: 8px;
}
</style>
This diff is collapsed.
This diff is collapsed.
<template>
<SellTemplate />
</template>
<script setup lang="ts">
import { ref, reactive, provide, watch, inject } from 'vue'
import SellTemplate from './SellTemplate.vue'
const datas = reactive({
SellDatas:{
activeId: 1,
}
})
provide('SellDatas',datas.SellDatas)
</script>
<style lang="scss" scoped>
.SellTemplate-form{
height: 100%;
}
</style>
\ No newline at end of file
<template>
<div class="column items-center animate__animated" :class="{'animate__fadeIn':props.top==0,'animate__fadeOut':props.top>0}">
<div class="animate__animated animate__fadeInDown logo">
<img src="https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713237911000_1.png" alt="">
</div>
<div class="animate__animated animate__fadeInUp" style="margin-top: 45px">
<img src="https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713237911000_838.png" style="width: 342px;">
</div>
<div class="animate__animated animate__fadeInUp text-center q-mt-xl text-info" style="width: 449px;font-size: 18px;">
可云端编辑的专业级行程设计工具,为旅游行业量身打造打开网页就可以做出精美行程。
</div>
<div class="animate__animated animate__fadeInUp linkToSpace cusor-pointer">立即使用</div>
<div class="animate__animated animate__fadeInUp">
<img src="https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713237911000_524.png" style="width: 1206px;">
</div>
</div>
<div class="first-card column items-center flex-center animate__animated animate__fadeIn" v-show="props.top>0">
<div>
<img src="https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713237911000_524.png" style="width: 1206px;">
</div>
</div>
</template>
<script lang="ts" setup>
const props = defineProps({
top: {
type: Number,
required: true,
}
})
</script>
<style scoped>
.website .logo{
margin-top: 188px;
}
.website .logo img{
width: 452px;
}
.website .text-info{
color:#625A7E;
}
.website .linkToSpace{
width:403px;
background-image: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713237911000_735.png');
height: 200px;
font-size: 26px;
color: #FFFFFF;
line-height: 200px;
text-shadow: 0px 0px 13px rgba(21,62,161,0.94);
text-align: center;
user-select: none;
}
.website .first-card{
position:absolute;
top: 0;
height: 100vh;
left: 0;
width: 100vw;
z-index: 1;
}
</style>
\ No newline at end of file
<template>
<el-scrollbar height="100vh" @scroll="onChange">
<div class="website">
<welcomes :top="top"></welcomes>
<div style="height: 1200px;background-color: #000;margin-top: 500px;"></div>
</div>
</el-scrollbar>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import welcomes from './components/welcomes.vue';
const top = ref(0)
const onChange = (e:any)=>{
top.value = e.scrollTop
}
</script>
<style scoped>
.website{
background-image: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1713237911000_863.png');
width: 100vw;
min-height: 100vh;
background-repeat: repeat-y;
background-size: 100% auto;
}
</style>
\ No newline at end of file
......@@ -5,7 +5,7 @@ import type { PPTElementOutline } from '@/types/slides'
export default (outline: Ref<PPTElementOutline | undefined>) => {
const outlineWidth = computed(() => outline.value?.width ?? 0)
const outlineStyle = computed(() => outline.value?.style || 'solid')
const outlineColor = computed(() => outline.value?.color || '#d14424')
const outlineColor = computed(() => outline.value?.color || '#564bec')
const strokeDashArray = computed(() => {
if (outlineStyle.value !== 'dashed') return '0 0'
......
......@@ -40,7 +40,7 @@ module.exports = {
},
pwa: {
name: 'PPTist',
themeColor: '#d14424',
themeColor: '#564bec', //#d14424
iconPaths: {
faviconSVG: null,
favicon32: 'icons/favicon-32x32.png',
......@@ -52,7 +52,7 @@ module.exports = {
manifestOptions: {
name: 'PPTist',
short_name: 'PPTist',
theme_color: '#d14424',
theme_color: '#564bec',
icons: [{
src: 'icons/android-chrome-192x192.png',
sizes: '192x192',
......
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