新版本官网优化完成
This commit is contained in:
@@ -95,9 +95,9 @@ export async function removeBatchCmsWebsite(data: (number | undefined)[]) {
|
|||||||
/**
|
/**
|
||||||
* 根据id查询网站信息记录表
|
* 根据id查询网站信息记录表
|
||||||
*/
|
*/
|
||||||
export async function getCmsWebsite(id: number) {
|
export async function getCmsWebsiteAll(id: number) {
|
||||||
const res = await request.get<ApiResult<CmsWebsite>>(
|
const res = await request.get<ApiResult<CmsWebsite>>(
|
||||||
'https://cms-api.websoft.top/api/cms/cms-website/' + id
|
'/cms/cms-website/all/' + id
|
||||||
);
|
);
|
||||||
if (res.code === 0 && res.data) {
|
if (res.code === 0 && res.data) {
|
||||||
return res.data;
|
return res.data;
|
||||||
@@ -120,7 +120,7 @@ export async function removeSiteInfoCache(key?: string) {
|
|||||||
|
|
||||||
export async function pageCmsWebsiteAll(params: CmsWebsiteParam) {
|
export async function pageCmsWebsiteAll(params: CmsWebsiteParam) {
|
||||||
const res = await request.get<ApiResult<PageResult<CmsWebsite>>>(
|
const res = await request.get<ApiResult<PageResult<CmsWebsite>>>(
|
||||||
'https://cms-api.websoft.top/api/cms/cms-website/pageAll',
|
'/cms/cms-website/pageAll',
|
||||||
{
|
{
|
||||||
params
|
params
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ export interface CmsWebsite {
|
|||||||
websiteDarkLogo?: string;
|
websiteDarkLogo?: string;
|
||||||
// 网站类型
|
// 网站类型
|
||||||
websiteType?: string;
|
websiteType?: string;
|
||||||
|
// 评分
|
||||||
|
rate?: number;
|
||||||
|
// 点赞数
|
||||||
|
likes?: number;
|
||||||
|
// 点击量
|
||||||
|
clicks?: number;
|
||||||
|
// 购买量
|
||||||
|
buys?: number;
|
||||||
|
// 下载安装
|
||||||
|
downloads?: number;
|
||||||
// 网站截图
|
// 网站截图
|
||||||
files?: string;
|
files?: string;
|
||||||
// 网站关键词
|
// 网站关键词
|
||||||
@@ -106,5 +116,6 @@ export interface CmsWebsite {
|
|||||||
export interface CmsWebsiteParam extends PageParam {
|
export interface CmsWebsiteParam extends PageParam {
|
||||||
websiteId?: number;
|
websiteId?: number;
|
||||||
status?: number;
|
status?: number;
|
||||||
|
recommend?: number;
|
||||||
keywords?: string;
|
keywords?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ export async function getSiteInfo(params: CmsWebsiteParam) {
|
|||||||
*/
|
*/
|
||||||
export async function getUserInfo(): Promise<User> {
|
export async function getUserInfo(): Promise<User> {
|
||||||
const config = useRuntimeConfig();
|
const config = useRuntimeConfig();
|
||||||
const res = await request.get<ApiResult<User>>(config.public.apiServer + '/auth/user');
|
const res = await request.get<ApiResult<User>>(config.public.apiServer + '/auth/user',{
|
||||||
|
headers: {
|
||||||
|
TenantId: `${localStorage.getItem('TID_ADMIN')}`
|
||||||
|
}
|
||||||
|
});
|
||||||
if (res.code === 0 && res.data) {
|
if (res.code === 0 && res.data) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
SmsCaptchaResult
|
SmsCaptchaResult
|
||||||
} from './model';
|
} from './model';
|
||||||
import { SERVER_API_URL } from '~/config';
|
import { SERVER_API_URL } from '~/config';
|
||||||
|
import type {UserParam} from "~/api/system/user/model";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
@@ -49,18 +50,22 @@ export async function loginBySms(data: LoginParam) {
|
|||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
console.log(res.data,'登录成功')
|
return res.data;
|
||||||
// setToken(res.data.data?.access_token, data.remember);
|
}
|
||||||
// if (res.data.data?.user) {
|
return Promise.reject(new Error(res.message));
|
||||||
// const user = res.data.data?.user;
|
}
|
||||||
// localStorage.setItem('TenantId', String(user.tenantId));
|
|
||||||
// localStorage.setItem('Phone', String(user.phone));
|
|
||||||
// localStorage.setItem('UserId', String(user.userId));
|
|
||||||
// localStorage.setItem('MerchantId', String(user.merchantId));
|
|
||||||
// localStorage.setItem('MerchantName', String(user.merchantName));
|
|
||||||
// }
|
|
||||||
|
|
||||||
return res.message;
|
/**
|
||||||
|
* 用户注册
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export async function register(data: UserParam) {
|
||||||
|
const res = await request.post<ApiResult<LoginResult>>(
|
||||||
|
SERVER_API_URL + '/register',
|
||||||
|
data
|
||||||
|
);
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.data;
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error(res.message));
|
return Promise.reject(new Error(res.message));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ export interface LoginParam {
|
|||||||
phone?: string;
|
phone?: string;
|
||||||
// 短信验证码
|
// 短信验证码
|
||||||
code?: string;
|
code?: string;
|
||||||
|
// 是否超级管理员
|
||||||
|
isSuperAdmin?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ export interface UserParam extends PageParam {
|
|||||||
type?: any;
|
type?: any;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
username?: string;
|
username?: string;
|
||||||
|
password?: string;
|
||||||
nickname?: string;
|
nickname?: string;
|
||||||
realName?: string;
|
realName?: string;
|
||||||
gradeId?: unknown;
|
gradeId?: unknown;
|
||||||
@@ -144,12 +145,15 @@ export interface UserParam extends PageParam {
|
|||||||
cityMate?: string;
|
cityMate?: string;
|
||||||
sex?: string;
|
sex?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
|
email?: string;
|
||||||
|
code?: string;
|
||||||
status?: number;
|
status?: number;
|
||||||
organizationId?: number;
|
organizationId?: number;
|
||||||
parentId?: number;
|
parentId?: number;
|
||||||
sexName?: string;
|
sexName?: string;
|
||||||
roleId?: string;
|
roleId?: string;
|
||||||
isAdmin?: number;
|
isAdmin?: number;
|
||||||
|
isSuperAdmin?: boolean;
|
||||||
showProfile?: boolean;
|
showProfile?: boolean;
|
||||||
isStaff?: boolean;
|
isStaff?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2329,7 +2329,6 @@ h3.tag a:hover {
|
|||||||
.relate h4 {
|
.relate h4 {
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
border-bottom: 1px solid #0c6fcd;
|
border-bottom: 1px solid #0c6fcd;
|
||||||
padding-left: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#relate_p .img img {
|
#relate_p .img img {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg width="70" height="70" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="17.621%" y1="50%" x2="100%" y2="50%" id="a"><stop stop-color="#FFE2B8" offset="0%"/><stop stop-color="#FFCA7C" offset="100%"/></linearGradient><filter x="-10.7%" y="-10.7%" width="121.4%" height="121.4%" filterUnits="objectBoundingBox" id="c"><feGaussianBlur stdDeviation="6" in="SourceAlpha" result="shadowBlurInner1"/><feOffset dx="3" in="shadowBlurInner1" result="shadowOffsetInner1"/><feComposite in="shadowOffsetInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowInnerInner1"/></filter><path id="b" d="m1291 377 70 70v-70z"/></defs><g transform="translate(-1291 -377)" fill="none" fill-rule="evenodd"><use fill="url(#a)" xlink:href="#b"/><use fill="#000" filter="url(#c)" xlink:href="#b"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 953 B |
@@ -1,23 +1,74 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="fr clearfix flex items-center">
|
<div class="fr clearfix flex items-center">
|
||||||
<!-- <div class="fl mr-5">-->
|
<div class="fl mr-5">
|
||||||
<!-- <el-input v-model="keyword" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="onSearch"/>-->
|
<el-input v-model="keywords" :placeholder="`${$t('searchKeywords')}`" :suffix-icon="Search" @change="onSearch"/>
|
||||||
<!-- </div>-->
|
</div>
|
||||||
<div class="lang flex justify-center text-center items-center">
|
<!-- 未登录 -->
|
||||||
|
<div v-if="!token" class="lang flex justify-center text-center items-center">
|
||||||
<el-space>
|
<el-space>
|
||||||
<nuxt-link to="https://oa.websoft.top/register" type="text" class="text-sm text-gray-500">注册</nuxt-link>
|
<nuxt-link to="/passport/login?type=register" type="text" class="text-sm text-gray-500">注册</nuxt-link>
|
||||||
<el-divider direction="vertical"/>
|
<el-divider direction="vertical"/>
|
||||||
<nuxt-link to="https://oa.websoft.top/passport/login" type="text" class="text-sm text-gray-500">登录</nuxt-link>
|
<nuxt-link to="/passport/login" type="text" class="text-sm text-gray-500">登录</nuxt-link>
|
||||||
</el-space>
|
</el-space>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 已登录 -->
|
||||||
|
<div v-else>
|
||||||
|
<div class="header__right items-center pr-4 xl:pr-0 md:flex hidden">
|
||||||
|
<el-space class="sm:flex hidden" size="large">
|
||||||
|
<ClientOnly>
|
||||||
|
<template v-if="token">
|
||||||
|
<el-dropdown @command="handleCommand">
|
||||||
|
<el-space class="flex items-center cursor-pointer">
|
||||||
|
<el-avatar class="cursor-pointer" :src="user?.avatar" :size="30" />
|
||||||
|
<span>{{ user?.tenantName }}</span>
|
||||||
|
</el-space>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="user"><nuxt-link to="/user">用户中心</nuxt-link></el-dropdown-item>
|
||||||
|
<el-dropdown-item command="password"><nuxt-link to="/user/password">修改密码</nuxt-link></el-dropdown-item>
|
||||||
|
<el-dropdown-item command="auth"><nuxt-link to="/user/auth">实名认证</nuxt-link></el-dropdown-item>
|
||||||
|
<el-dropdown-item divided command="order"><nuxt-link to="/user/order">我的订单</nuxt-link></el-dropdown-item>
|
||||||
|
<el-dropdown-item divided command="logOut"><nuxt-link to="/user/logout">退出登录</nuxt-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-button type="primary" v-if="!token" @click="navigateTo(`/passport/login`)">登录/注册</el-button>
|
||||||
|
<!-- <el-button v-if="config.showLoginButton" circle :icon="ElIconUserFilled" @click="goLogin"></el-button>-->
|
||||||
|
</template>
|
||||||
|
</ClientOnly>
|
||||||
|
</el-space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Search } from '@element-plus/icons-vue'
|
import { Search } from '@element-plus/icons-vue'
|
||||||
const keyword = ref<string>('');
|
const token = useToken();
|
||||||
|
const user = useUser();
|
||||||
|
const keywords = ref<string>();
|
||||||
|
|
||||||
const onSearch = () => {
|
const onSearch = () => {
|
||||||
window.location.href = `/search/${keyword.value}`;
|
navigateTo(`/search/${keywords.value || '关键词不能为空!'}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCommand(command: string) {
|
||||||
|
switch (command) {
|
||||||
|
case 'logOut':
|
||||||
|
logOut();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
navigateTo('/user');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function logOut() {
|
||||||
|
token.value = '';
|
||||||
|
localStorage.clear();
|
||||||
|
navigateTo('/passport/login')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 自定义banner -->
|
<!-- 自定义banner -->
|
||||||
<div class="banner m-auto relative sm:flex hidden-sm-and-down flex justify-center">
|
<div v-if="layout?.banner" class="banner m-auto relative sm:flex hidden-sm-and-down flex justify-center">
|
||||||
<el-image :src="layout?.banner" class="min-h-sm sm:h-auto w-full"></el-image>
|
<el-image :src="layout?.banner" class="min-h-sm sm:h-auto w-full"></el-image>
|
||||||
<div class="banner-bar absolute top-0 w-full sm:flex hidden">
|
<div class="banner-bar absolute top-0 w-full sm:flex hidden">
|
||||||
<div class="banner-text py-12 md:w-screen-xl m-auto opacity-90 flex flex-col justify-center">
|
<div class="banner-text py-12 md:w-screen-xl m-auto opacity-90 flex flex-col justify-center">
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relatenew relate"><h4>{{ $t('articleRelated')}}:</h4>
|
<div class="relatenew relate"><h4>{{ $t('articleRelated')}}:</h4>
|
||||||
<div class="p-1">
|
<div class="py-1">
|
||||||
<ul id="relate_n" class="news_list clearfix">
|
<ul id="relate_n" class="news_list clearfix">
|
||||||
<li v-for="(item,index) in list" :key="index"><a :href="detail(item)" :title="item.title">{{ item.title }}</a></li>
|
<li v-for="(item,index) in list" :key="index"><a :href="detail(item)" :title="item.title">{{ item.title }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const reload = () => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="relateproduct relate">
|
<div class="relateproduct relate">
|
||||||
<h4>{{ $t('recentlyViewed') }}:</h4>
|
<h4>{{ $t('recentlyViewed') }}:</h4>
|
||||||
<div class="p-1" v-if="type == 'article'">
|
<div class="py-1" v-if="type == 'article'">
|
||||||
<ul id="relate_n" class="news_list clearfix">
|
<ul id="relate_n" class="news_list clearfix">
|
||||||
<li v-for="(item,index) in list" :key="index"><a :href="detail(item)" :title="item.title">{{ item.title }}</a></li>
|
<li v-for="(item,index) in list" :key="index"><a :href="detail(item)" :title="item.title">{{ item.title }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -10,19 +10,18 @@ const props = withDefaults(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="text-[16px]" v-html="data"></div>
|
<div v-html="data"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.content {
|
.content {
|
||||||
padding-top: 15px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: #333131;
|
color: #333131;
|
||||||
}
|
}
|
||||||
.content p{
|
.content p{
|
||||||
padding: 0;
|
padding: 0;
|
||||||
line-height: 2.2rem;
|
line-height: 2.2rem;
|
||||||
text-indent: 2rem;
|
//text-indent: 2rem;
|
||||||
}
|
}
|
||||||
.content img{
|
.content img{
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
|
|||||||
@@ -29,14 +29,24 @@ nextArticle.value = await getNext({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page flex flex-col">
|
<div class="flex justify-between my-3 gap-4">
|
||||||
<span class="text-left">
|
<nuxt-link :to="previousArticle ? detail(previousArticle) : ''" class="w-[50%] flex flex-col justify-center p-4 border-1 border-solid border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50">
|
||||||
{{ $t('previous') }}:<a :href="detail(previousArticle)">{{ previousArticle?.title }}</a>
|
<span class="text-lg text-gray-800">{{ previousArticle?.title || '没有了' }}</span>
|
||||||
</span>
|
<span class="text-gray-400">{{ $t('previous') }}</span>
|
||||||
<span class="text-left">
|
</nuxt-link>
|
||||||
{{ $t('next') }}:<a :href="detail(nextArticle)">{{ nextArticle?.title }}</a>
|
<nuxt-link :to="nextArticle ? detail(nextArticle) : ''" class="w-[50%] flex flex-col justify-center p-4 border-1 border-solid border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50">
|
||||||
</span>
|
<span class="text-lg text-gray-800">{{ nextArticle?.title || '没有了' }}</span>
|
||||||
|
<span class="text-gray-400">{{ $t('next') }}</span>
|
||||||
|
</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- <div class="page flex flex-col">-->
|
||||||
|
<!-- <span class="text-left">-->
|
||||||
|
<!-- {{ $t('previous') }}:<a :href="detail(previousArticle)">{{ previousArticle?.title }}</a>-->
|
||||||
|
<!-- </span>-->
|
||||||
|
<!-- <span class="text-left">-->
|
||||||
|
<!-- {{ $t('next') }}:<a :href="detail(nextArticle)">{{ nextArticle?.title }}</a>-->
|
||||||
|
<!-- </span>-->
|
||||||
|
<!-- </div>-->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const props = withDefaults(
|
|||||||
data?: any;
|
data?: any;
|
||||||
total?: number;
|
total?: number;
|
||||||
size?: ComponentSize;
|
size?: ComponentSize;
|
||||||
|
pageSize?: number;
|
||||||
}>(),
|
}>(),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
@@ -28,7 +29,7 @@ const mobile = useIsMobile();
|
|||||||
const where = reactive<CmsArticleParam>({
|
const where = reactive<CmsArticleParam>({
|
||||||
keywords: '',
|
keywords: '',
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 20,
|
limit: props.pageSize || 12,
|
||||||
status: 0,
|
status: 0,
|
||||||
parentId: undefined,
|
parentId: undefined,
|
||||||
categoryId: undefined,
|
categoryId: undefined,
|
||||||
|
|||||||
52
components/SearchBar.vue
Normal file
52
components/SearchBar.vue
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<el-space class="flex items-center">
|
||||||
|
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search"/>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Search } from '@element-plus/icons-vue'
|
||||||
|
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
|
||||||
|
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
buyUrl?: string;
|
||||||
|
form?: CmsArticle;
|
||||||
|
value?: number;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<any>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
navigateTo(`/search/${where.keywords}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.rounded-avatar {
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded-avatar-xs {
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -56,7 +56,12 @@ export const useProductAffix = () =>
|
|||||||
export const useSysDomain = () => useState('SysDomain', () => '');
|
export const useSysDomain = () => useState('SysDomain', () => '');
|
||||||
|
|
||||||
// 登录凭证
|
// 登录凭证
|
||||||
export const useToken = () => useState('token', () => '');
|
export const useToken = () => useState('token', () => {
|
||||||
|
if(localStorage.getItem('token')){
|
||||||
|
return localStorage.getItem('token')
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
});
|
||||||
|
|
||||||
// 用户信息
|
// 用户信息
|
||||||
export const useUser = () =>
|
export const useUser = () =>
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
"label": "标签",
|
"label": "标签",
|
||||||
"seeMore": "查看更多",
|
"seeMore": "查看更多",
|
||||||
"onlineInquiry": "在线询价",
|
"onlineInquiry": "在线询价",
|
||||||
"searchKeywords": "搜索关键词",
|
"searchKeywords": "站内搜索",
|
||||||
"tel": "电话",
|
"tel": "电话",
|
||||||
"map": "地图",
|
"map": "地图",
|
||||||
"message": "留言"
|
"message": "留言"
|
||||||
|
|||||||
@@ -6,13 +6,8 @@
|
|||||||
<template #content>
|
<template #content>
|
||||||
<span class="text-large font-600 mr-3"> {{ page.title }} </span>
|
<span class="text-large font-600 mr-3"> {{ page.title }} </span>
|
||||||
</template>
|
</template>
|
||||||
<template #extra>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="reload"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-row :gutter="24" id="container" class="clearfix">
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
<el-col v-for="(item,index) in list" :key="index" :span="6" class="left">
|
<el-col v-for="(item,index) in list" :key="index" :span="6" class="left mb-6">
|
||||||
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer" @click="navigateTo(`/detail/${item.articleId}.html`)">
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer" @click="navigateTo(`/detail/${item.articleId}.html`)">
|
||||||
<el-image
|
<el-image
|
||||||
:src="item.image"
|
:src="item.image"
|
||||||
@@ -24,9 +19,9 @@
|
|||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-1.5 py-2 text-gray-500 justify-between">
|
<!-- <div class="flex items-center gap-1.5 py-2 text-gray-500 justify-between">-->
|
||||||
<div class="text-gray-500 line-clamp-2">{{ item.comments }}</div>
|
<!-- <div class="text-gray-500 line-clamp-2">{{ item.comments }}</div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
||||||
<el-space class="flex items-end">
|
<el-space class="flex items-end">
|
||||||
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
||||||
@@ -117,7 +112,6 @@ const reload = async () => {
|
|||||||
|
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
router.back(); // 返回上一页
|
router.back(); // 返回上一页
|
||||||
// window.history.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
173
pages/case/index.vue
Normal file
173
pages/case/index.vue
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> {{ page.title || '客户案例' }} </span>
|
||||||
|
</template>
|
||||||
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
|
<el-col v-for="(item,index) in list" :key="index" :span="6" class="left">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer" @click="navigateTo(`/detail/${item.articleId}.html`)">
|
||||||
|
<el-image
|
||||||
|
:src="item.image"
|
||||||
|
fit="cover"
|
||||||
|
:lazy="true" class="w-full md:h-[166px] h-[199px] cursor-pointer bg-gray-50"/>
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-6 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col gap-1.5">
|
||||||
|
<div class="flex-1 text-xl cursor-pointer flex items-center">
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5 py-2 text-gray-500 justify-between">
|
||||||
|
<div class="text-gray-500 line-clamp-2">{{ item.comments }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
||||||
|
<el-space class="flex items-end">
|
||||||
|
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
||||||
|
</el-space>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
{{ dayjs(item.createTime).format('YYYY-MM-DD') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-page-header>
|
||||||
|
|
||||||
|
<Pagination :total="total" @done="search" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Banner from "@/components/Banner.vue";
|
||||||
|
import { ArrowLeft,View, Search } from '@element-plus/icons-vue'
|
||||||
|
import { ElNotification as notify } from 'element-plus'
|
||||||
|
import {useConfigInfo, useLayout, usePage} from "~/composables/configState";
|
||||||
|
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
||||||
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
|
import type { ComponentSize } from 'element-plus'
|
||||||
|
import { ElNotification } from 'element-plus'
|
||||||
|
import type { TabsPaneContext } from 'element-plus'
|
||||||
|
import { h } from 'vue'
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {detail, getNavIdByParamsId, navTo, paramsId} from "~/utils/common";
|
||||||
|
import Left from "~/components/Left.vue";
|
||||||
|
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
||||||
|
import {pageCmsArticle} from "~/api/cms/cmsArticle";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const navId = ref();
|
||||||
|
// 页面信息
|
||||||
|
const list = ref<CmsArticle[]>([]);
|
||||||
|
const i18n = useI18n();
|
||||||
|
const category = ref<CmsNavigation[]>([]);
|
||||||
|
const total = ref(0);
|
||||||
|
const activeName = ref('2839');
|
||||||
|
|
||||||
|
// 获取状态
|
||||||
|
const page = usePage();
|
||||||
|
const layout = useLayout();
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<CmsArticleParam>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
model: 'case',
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载页面数据
|
||||||
|
const reload = async () => {
|
||||||
|
pageCmsArticle(where).then(response => {
|
||||||
|
if(response){
|
||||||
|
total.value = response.count;
|
||||||
|
list.value = response.list;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// seo
|
||||||
|
// useSeoMeta({
|
||||||
|
// description: data.comments || data.title,
|
||||||
|
// keywords: data.title,
|
||||||
|
// titleTemplate: `${data?.title}` + ' - %s',
|
||||||
|
// })
|
||||||
|
|
||||||
|
// 二级栏目分类
|
||||||
|
// listCmsNavigation({}).then(navigation => {
|
||||||
|
// category.value = navigation;
|
||||||
|
// // 加载文章列表
|
||||||
|
// if(data.parentId == 0 && category.value.length > 0){
|
||||||
|
// where.parentId = page.value.navigationId;
|
||||||
|
// }else {
|
||||||
|
// where.categoryId = page.value.navigationId;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// })
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const search = (data: CmsArticleParam) => {
|
||||||
|
where.page = data.page;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||||
|
console.log(tab, event)
|
||||||
|
}
|
||||||
|
const value = ref('')
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: 'Option1',
|
||||||
|
label: 'Option1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option2',
|
||||||
|
label: 'Option2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option3',
|
||||||
|
label: 'Option3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option4',
|
||||||
|
label: 'Option4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option5',
|
||||||
|
label: 'Option5',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
() => {
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.right .content img{
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.demo-tabs > .el-tabs__content {
|
||||||
|
padding: 32px;
|
||||||
|
color: #6b778c;
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,40 +6,61 @@
|
|||||||
<template #content>
|
<template #content>
|
||||||
<span class="font-600 mr-3"> 文章详情 </span>
|
<span class="font-600 mr-3"> 文章详情 </span>
|
||||||
</template>
|
</template>
|
||||||
<template #extra>
|
|
||||||
<div class="flex items-center">
|
<el-card shadow="hover" class=" my-5 px-2">
|
||||||
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="reload"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-card shadow="hover" class=" my-5">
|
|
||||||
|
|
||||||
<!-- 新闻详细 -->
|
<!-- 新闻详细 -->
|
||||||
<div class="news_detail bg-white">
|
<div class=" bg-white">
|
||||||
<h1 class="pt-5 text-2xl">{{ form.title }}</h1>
|
<h1 class="pt-5 text-3xl">{{ form.title }}</h1>
|
||||||
<div class="clearfix">
|
<div class="flex items-center justify-between py-4">
|
||||||
<h3 class=" text-gray-400">
|
<el-space size="large" class="text-gray-400">
|
||||||
{{ $t('createTime') }}:<span>{{ dayjs(form.createTime).format('YYYY-MM-DD') }}</span>
|
<span>{{ $t('createTime') }}:{{ dayjs(form.createTime).format('YYYY-MM-DD') }}</span>
|
||||||
{{ $t('author') }}:<span>{{ form.nickname }}</span>
|
<span>{{ $t('author') }}:{{ form.author }}</span>
|
||||||
{{ $t('click') }}:<span>{{ getViews(form) }}</span>
|
<span>{{ $t('click') }}:{{ getViews(form) }}</span>
|
||||||
</h3>
|
<span v-if="form.source">文章来源:{{ form.source }}</span>
|
||||||
<div class="share">
|
</el-space>
|
||||||
<!-- Baidu Button BEGIN -->
|
<!-- Baidu Button BEGIN -->
|
||||||
<div class="bdsharebuttonbox">
|
<el-space class="flex items-center">
|
||||||
<a href="#" class="bds_more" data-cmd="more"></a>
|
<!-- <a href="#" class="bds_more" data-cmd="more">朋友圈</a>-->
|
||||||
<a href="#" class="bds_qzone" data-cmd="qzone"></a>
|
<!-- <a href="#" class="bds_qzone" data-cmd="qzone">QQ空间</a>-->
|
||||||
<a href="#" class="bds_tsina" data-cmd="tsina"></a>
|
<!-- <a href="#" class="bds_tsina" data-cmd="tsina">新浪</a>-->
|
||||||
<a href="#" class="bds_tqq" data-cmd="tqq"></a>
|
<!-- <a href="#" class="bds_tqq" data-cmd="tqq">腾讯</a>-->
|
||||||
<a href="#" class="bds_renren" data-cmd="renren"></a>
|
<!-- <a href="#" class="bds_weixin" data-cmd="weixin">微信</a>-->
|
||||||
<a href="#" class="bds_weixin" data-cmd="weixin"></a>
|
</el-space>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 文章摘要 -->
|
||||||
|
<div v-if="form.comments" class="screen-item bg-orange-50 text-gray-600 p-3 text-lg">
|
||||||
|
{{ form.comments }}
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 文章附件 -->
|
||||||
|
<div class="screen-item" v-if="form.files">
|
||||||
|
<div class="text-gray-400 py-3 text-sm">图片附件</div>
|
||||||
|
<el-scrollbar>
|
||||||
|
<div class="flex">
|
||||||
|
<el-image
|
||||||
|
v-for="(item,index) in JSON.parse(form.files)"
|
||||||
|
:key="index"
|
||||||
|
class="scrollbar-item w-[240px] max-h-[180px] mr-4 mb-4"
|
||||||
|
:src="item"
|
||||||
|
:zoom-rate="1.2"
|
||||||
|
:max-scale="7"
|
||||||
|
:min-scale="0.2"
|
||||||
|
:preview-src-list="srcList"
|
||||||
|
:initial-index="4"
|
||||||
|
fit="contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
<!-- 内容组件 -->
|
<!-- 内容组件 -->
|
||||||
<Content class="content" :data="form.content" />
|
<Content class="content text-lg py-5" :data="form.content" />
|
||||||
|
|
||||||
|
<NextArticle :articleId="articleId" />
|
||||||
<h3 class="tag">{{ $t('articleUrl') }}:{{ locationUrl() }} </h3>
|
<h3 class="tag">{{ $t('articleUrl') }}:{{ locationUrl() }} </h3>
|
||||||
<Tags :data="form.tags" />
|
<Tags :data="form.tags" />
|
||||||
<NextArticle :articleId="articleId" />
|
|
||||||
</div>
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
|
||||||
<!-- 最近浏览 -->
|
<!-- 最近浏览 -->
|
||||||
<CmsArticleRecently :data="form" type="article" />
|
<CmsArticleRecently :data="form" type="article" />
|
||||||
@@ -49,7 +70,6 @@
|
|||||||
<CmsArticleRelated :data="form" />
|
<CmsArticleRelated :data="form" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</el-card>
|
|
||||||
</el-page-header>
|
</el-page-header>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -61,9 +81,7 @@ import {getNavIdByParamsId, getViews, locationUrl, navTo, paramsId} from "~/util
|
|||||||
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
import useFormData from "~/utils/use-form-data";
|
import useFormData from "~/utils/use-form-data";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import Banner from "@/components/Banner.vue";
|
|
||||||
import type {Layout} from "~/api/layout/model";
|
import type {Layout} from "~/api/layout/model";
|
||||||
import Left from "~/components/Left.vue";
|
|
||||||
import {
|
import {
|
||||||
getCmsArticle
|
getCmsArticle
|
||||||
} from "~/api/cms/cmsArticle";
|
} from "~/api/cms/cmsArticle";
|
||||||
@@ -71,8 +89,6 @@ import {listCmsNavigation} from "~/api/cms/cmsNavigation";
|
|||||||
import CmsArticleRecently from "~/components/CmsRecently.vue";
|
import CmsArticleRecently from "~/components/CmsRecently.vue";
|
||||||
import Tags from "~/components/Tags.vue";
|
import Tags from "~/components/Tags.vue";
|
||||||
import Content from "~/components/Content.vue";
|
import Content from "~/components/Content.vue";
|
||||||
import CmsArticleList from "~/components/CmsArticleList.vue";
|
|
||||||
import PageBanner from "~/pages/item/components/PageBanner.vue";
|
|
||||||
|
|
||||||
// 引入状态管理
|
// 引入状态管理
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -83,6 +99,7 @@ const i18n = useI18n();
|
|||||||
const breadcrumb = ref<BreadcrumbItem>();
|
const breadcrumb = ref<BreadcrumbItem>();
|
||||||
const showPassword = ref<boolean>();
|
const showPassword = ref<boolean>();
|
||||||
const category = ref<CmsNavigation[]>([]);
|
const category = ref<CmsNavigation[]>([]);
|
||||||
|
const srcList = ref<any[]>([]);
|
||||||
|
|
||||||
// 配置信息
|
// 配置信息
|
||||||
const {form, assignFields} = useFormData<CmsArticle>({
|
const {form, assignFields} = useFormData<CmsArticle>({
|
||||||
@@ -182,6 +199,13 @@ const reload = async () => {
|
|||||||
await getCmsArticle(articleId.value).then(data => {
|
await getCmsArticle(articleId.value).then(data => {
|
||||||
assignFields(data)
|
assignFields(data)
|
||||||
layout.value.banner = data?.banner;
|
layout.value.banner = data?.banner;
|
||||||
|
// 应用截图
|
||||||
|
if(data.files){
|
||||||
|
const imgArr = JSON.parse(data.files);
|
||||||
|
imgArr.map((item: any) => {
|
||||||
|
srcList.value.push(item)
|
||||||
|
})
|
||||||
|
}
|
||||||
// 二级栏目分类
|
// 二级栏目分类
|
||||||
if (data.parentId) {
|
if (data.parentId) {
|
||||||
listCmsNavigation({parentId: data.parentId}).then(list => {
|
listCmsNavigation({parentId: data.parentId}).then(list => {
|
||||||
@@ -223,4 +247,14 @@ watch(
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
||||||
|
.scrollbar-flex-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.scrollbar-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
137
pages/docs/[id].vue
Normal file
137
pages/docs/[id].vue
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<Banner :layout="layout" />
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> {{ page.title }} </span>
|
||||||
|
</template>
|
||||||
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
|
<el-col v-for="(item,index) in list" :key="index" :span="6" class="left mb-6">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer" @click="navigateTo(`/detail/${item.articleId}.html`)">
|
||||||
|
<el-image
|
||||||
|
:src="item.image"
|
||||||
|
fit="cover"
|
||||||
|
:lazy="true" class="w-full md:h-[166px] h-[199px] cursor-pointer bg-gray-50"/>
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-6 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col gap-1.5">
|
||||||
|
<div class="flex-1 text-xl cursor-pointer flex min-h-[56px]">
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="flex items-center gap-1.5 py-2 text-gray-500 justify-between">-->
|
||||||
|
<!-- <div class="text-gray-500 line-clamp-2">{{ item.comments }}</div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
||||||
|
<el-space class="flex items-end">
|
||||||
|
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
||||||
|
</el-space>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
<el-avatar v-if="item.avatar" size="small" :src="`${item.avatar}`" />
|
||||||
|
{{ dayjs(item.createTime).format('YYYY-MM-DD') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-page-header>
|
||||||
|
<Pagination :total="total" @done="search" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useLayout, usePage} from "~/composables/configState";
|
||||||
|
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
||||||
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
|
import {getNavIdByParamsId, getViews, paramsId} from "~/utils/common";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
||||||
|
import {pageCmsArticle} from "~/api/cms/cmsArticle";
|
||||||
|
import Banner from "~/components/Banner.vue";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const navId = ref();
|
||||||
|
const list = ref<CmsArticle[]>([]);
|
||||||
|
const i18n = useI18n();
|
||||||
|
const category = ref<CmsNavigation[]>([]);
|
||||||
|
const total = ref<number>(0);
|
||||||
|
|
||||||
|
// 获取状态
|
||||||
|
const page = usePage();
|
||||||
|
const layout = useLayout();
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<CmsArticleParam>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载页面数据
|
||||||
|
const reload = async () => {
|
||||||
|
getCmsNavigation(navId.value).then(data => {
|
||||||
|
// 获取栏目信息
|
||||||
|
page.value = data
|
||||||
|
layout.value.banner = data.banner;
|
||||||
|
|
||||||
|
// 设置页面标题
|
||||||
|
useSeoMeta({
|
||||||
|
description: data.comments || data.title,
|
||||||
|
keywords: data.title,
|
||||||
|
titleTemplate: `${data?.title}` + ' - %s',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 二级栏目分类
|
||||||
|
listCmsNavigation({
|
||||||
|
parentId: data.parentId == 0 ? data.navigationId : data.parentId
|
||||||
|
}).then(categoryData => {
|
||||||
|
category.value = categoryData;
|
||||||
|
console.log(categoryData)
|
||||||
|
// 加载文章列表
|
||||||
|
if(data.parentId == 0 && category.value.length > 0){
|
||||||
|
where.parentId = data.navigationId;
|
||||||
|
}else {
|
||||||
|
where.categoryId = data.navigationId;
|
||||||
|
}
|
||||||
|
pageCmsArticle(where).then(response => {
|
||||||
|
if(response){
|
||||||
|
total.value = response?.count;
|
||||||
|
list.value = response?.list;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err,'加载失败...')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
// window.history.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const search = (data: CmsArticleParam) => {
|
||||||
|
where.page = data.page;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(id) => {
|
||||||
|
navId.value = getNavIdByParamsId(id);
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
</script>
|
||||||
123
pages/docs/index.vue
Normal file
123
pages/docs/index.vue
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<Banner :layout="layout" />
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 文档中心 </span>
|
||||||
|
</template>
|
||||||
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
|
<el-col v-for="(item,index) in list" :key="index" :span="6" class="left mb-6">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-white cursor-pointer" @click="navigateTo(`/docs/${item.navigationId}.html`)">
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-4 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col items-center gap-1.5">
|
||||||
|
<el-avatar
|
||||||
|
:src="item.icon" shape="square" :size="100" style="background-color: white;"/>
|
||||||
|
<div class="flex-1 text-lg cursor-pointer flex flex-col text-left py-4">
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useLayout, usePage} from "~/composables/configState";
|
||||||
|
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
||||||
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
|
import {getNavIdByParamsId, getViews, paramsId} from "~/utils/common";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
||||||
|
import {pageCmsArticle} from "~/api/cms/cmsArticle";
|
||||||
|
import Banner from "~/components/Banner.vue";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const navId = ref();
|
||||||
|
const list = ref<CmsNavigation[]>([]);
|
||||||
|
const i18n = useI18n();
|
||||||
|
const category = ref<CmsNavigation[]>([]);
|
||||||
|
const total = ref<number>(0);
|
||||||
|
|
||||||
|
// 获取状态
|
||||||
|
const page = usePage();
|
||||||
|
const layout = useLayout();
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<CmsArticleParam>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载页面数据
|
||||||
|
const reload = async () => {
|
||||||
|
listCmsNavigation({model: 'docs'}).then(data => {
|
||||||
|
console.log(data,'123.')
|
||||||
|
list.value = data;
|
||||||
|
// 获取栏目信息
|
||||||
|
page.value = data
|
||||||
|
layout.value.banner = data.banner;
|
||||||
|
|
||||||
|
// 设置页面标题
|
||||||
|
useSeoMeta({
|
||||||
|
description: '文档中心',
|
||||||
|
keywords: '文档中心',
|
||||||
|
titleTemplate: `文档中心` + ' - %s',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 二级栏目分类
|
||||||
|
listCmsNavigation({
|
||||||
|
parentId: data.parentId == 0 ? data.navigationId : data.parentId
|
||||||
|
}).then(categoryData => {
|
||||||
|
category.value = categoryData;
|
||||||
|
console.log(categoryData)
|
||||||
|
// 加载文章列表
|
||||||
|
if(data.parentId == 0 && category.value.length > 0){
|
||||||
|
where.parentId = data.navigationId;
|
||||||
|
}else {
|
||||||
|
where.categoryId = data.navigationId;
|
||||||
|
}
|
||||||
|
pageCmsArticle(where).then(response => {
|
||||||
|
if(response){
|
||||||
|
total.value = response?.count;
|
||||||
|
// list.value = response?.list;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err,'加载失败...')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
// window.history.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const search = (data: CmsArticleParam) => {
|
||||||
|
where.page = data.page;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
() => {
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -1,41 +1,26 @@
|
|||||||
<!-- 文章详情 -->
|
|
||||||
<template>
|
<template>
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 产品详情 </span>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<div class="h-[32px]"></div>
|
||||||
|
</template>
|
||||||
<PageBanner :form="page" @done="reload"/>
|
<PageBanner :form="page" @done="reload"/>
|
||||||
<div class="page-main md:w-screen-xl m-auto p-3">
|
<el-divider />
|
||||||
<el-row :gutter="24">
|
<AppInfo :form="form" />
|
||||||
<el-col :span="18" :xs="24">
|
|
||||||
<el-card shadow="hover" class="mb-5">
|
<div class="screen-item my-6">
|
||||||
<el-descriptions title="参数信息" :column="2" border>
|
<el-descriptions title="截屏" />
|
||||||
<el-descriptions-item :span="2" label="产品名称">{{page.title}}</el-descriptions-item>
|
<el-scrollbar>
|
||||||
<el-descriptions-item v-if="form.isBuy" label="租户ID"><span class="text-orange-500">{{form.title}}</span></el-descriptions-item>
|
<div class="flex" v-if="form.files">
|
||||||
<el-descriptions-item v-if="form.isBuy" label="插件ID"><span class="text-orange-500">{{form.menuId || '-'}}</span></el-descriptions-item>
|
|
||||||
<el-descriptions-item label="控制台"><a class="cursor-pointer" @click="openUrl(`https://${form.domain}`)">{{form.domain}}</a></el-descriptions-item>
|
|
||||||
<el-descriptions-item v-for="(item,index) in form.parameters" :key="index" :label="item.name">{{ item.value }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
<template v-if="form.accounts && form.accounts.length > 0">
|
|
||||||
<div class="h-[24px]"></div>
|
|
||||||
<el-descriptions title="登录账号" :column="1" border>
|
|
||||||
<template v-for="(item,index) in form.accounts" :key="index">
|
|
||||||
<el-descriptions-item :label="item.type" v-if="item.account">
|
|
||||||
还没有账号? <el-button type="text" @click="openSpmUrl(`/passport/regis`)">立即注册</el-button>
|
|
||||||
</el-descriptions-item>
|
|
||||||
</template>
|
|
||||||
</el-descriptions>
|
|
||||||
</template>
|
|
||||||
<template v-if="form.gits && form.gits.length > 0">
|
|
||||||
<div class="h-[24px]"></div>
|
|
||||||
<el-descriptions title="代码仓库" :column="1" border>
|
|
||||||
<el-descriptions-item v-for="(item,index) in form.gits" :key="index" :label="item.title">
|
|
||||||
<el-input v-model="item.domain" readonly />
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</template>
|
|
||||||
<template v-if="form.files && form.files.length > 0">
|
|
||||||
<div class="h-[24px]"></div>
|
|
||||||
<el-descriptions title="图文详情" />
|
|
||||||
<div v-for="(item,index) in JSON.parse(form.files)" :key="index" class="text item">
|
|
||||||
<el-image
|
<el-image
|
||||||
:src="item"
|
v-for="(item,index) in JSON.parse(form.files)"
|
||||||
|
:key="index"
|
||||||
|
class="scrollbar-item w-[240px] max-h-[625px] mr-4 mb-3"
|
||||||
|
:src="item.url"
|
||||||
:zoom-rate="1.2"
|
:zoom-rate="1.2"
|
||||||
:max-scale="7"
|
:max-scale="7"
|
||||||
:min-scale="0.2"
|
:min-scale="0.2"
|
||||||
@@ -44,158 +29,147 @@
|
|||||||
fit="contain"
|
fit="contain"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</el-scrollbar>
|
||||||
<template v-if="form.content">
|
<p v-html="form?.content || '介绍'" class="content"></p>
|
||||||
<p v-html="form.content" class="content"></p>
|
</div>
|
||||||
</template>
|
|
||||||
</el-card>
|
<el-divider />
|
||||||
<!-- 产品评论 -->
|
<!-- 评分及评价 -->
|
||||||
<Comments :productId="form.companyId" :comments="comments" :count="commentsTotal" @done="doComments" />
|
<Comments :productId="form.companyId" :comments="comments" :count="commentsTotal" @done="doComments" />
|
||||||
</el-col>
|
<div class="h-[100px]"></div>
|
||||||
<el-col :span="6" :xs="24">
|
</el-page-header>
|
||||||
<el-card shadow="hover" class="mb-5">
|
|
||||||
<template #header>
|
|
||||||
<div class="card-header font-bold text-xl">
|
|
||||||
<span>推荐产品</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!-- <el-space class="flex items-center">-->
|
|
||||||
<!-- <div class="avatar">-->
|
|
||||||
<!-- <el-avatar :size="55" :src="form.image"/>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="flex flex-col">-->
|
|
||||||
<!-- <span class="font-bold text-lg text-gray-600">{{ form.title }}</span>-->
|
|
||||||
<!-- <span class="text-gray-400 pb-1 line-clamp-2">{{ form.comments }}</span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </el-space>-->
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Cpu,Download,Star,Coin,Tickets} from '@element-plus/icons-vue'
|
import { ArrowLeft,View, Monitor, Search,Cpu, Platform, Avatar } from '@element-plus/icons-vue'
|
||||||
import type {ApiResult, PageResult} from "~/api";
|
import type {ApiResult, PageResult} from "~/api";
|
||||||
import {useServerRequest} from "~/composables/useServerRequest";
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
import {useLayout, usePage, useWebsite} from "~/composables/configState";
|
import {usePage} from "~/composables/configState";
|
||||||
import type {BreadcrumbItem} from "~/types/global";
|
|
||||||
import {getIdBySpm, getNavIdByParamsId, openUrl} from "~/utils/common";
|
import {getIdBySpm, getNavIdByParamsId, openUrl} from "~/utils/common";
|
||||||
import useFormData from "~/utils/use-form-data";
|
import useFormData from "~/utils/use-form-data";
|
||||||
import PageBanner from './components/PageBanner.vue';
|
import PageBanner from './components/PageBanner.vue';
|
||||||
|
import AppInfo from './components/AppInfo.vue';
|
||||||
import Comments from './components/Comments.vue';
|
import Comments from './components/Comments.vue';
|
||||||
import type {Company} from "~/api/system/company/model";
|
|
||||||
import type {CompanyComment} from "~/api/system/companyComment/model";
|
import type {CompanyComment} from "~/api/system/companyComment/model";
|
||||||
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
import {getCmsWebsiteAll} from "~/api/cms/cmsWebsite";
|
||||||
import {getCmsArticle, pageCmsArticle} from "~/api/cms/cmsArticle";
|
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
||||||
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
|
||||||
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
|
||||||
|
|
||||||
// 引入状态管理
|
// 引入状态管理
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const page = usePage();
|
const page = usePage();
|
||||||
const layout = useLayout();
|
|
||||||
const category = ref<CmsNavigation[]>([]);
|
|
||||||
const i18n = useI18n();
|
|
||||||
const total = ref(0);
|
|
||||||
const list = ref<CmsArticle[]>([]);
|
|
||||||
const website = useWebsite();
|
|
||||||
const breadcrumb = ref<BreadcrumbItem>();
|
|
||||||
const comments = ref<CompanyComment[]>([]);
|
const comments = ref<CompanyComment[]>([]);
|
||||||
const commentsTotal = ref(0);
|
const commentsTotal = ref(0);
|
||||||
const commentsPage = ref(1);
|
const commentsPage = ref(1);
|
||||||
const navId = ref();
|
const navId = ref();
|
||||||
const activeName = ref();
|
|
||||||
const url =
|
|
||||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
|
|
||||||
const srcList = ref<any[]>([]);
|
const srcList = ref<any[]>([]);
|
||||||
|
|
||||||
// 配置信息
|
// 配置信息
|
||||||
const {form, assignFields} = useFormData<CmsArticle>({
|
const {form, assignFields} = useFormData<CmsWebsite>({
|
||||||
// 文章id
|
// 站点ID
|
||||||
articleId: undefined,
|
websiteId: undefined,
|
||||||
// 文章模型
|
// 网站名称
|
||||||
model: undefined,
|
websiteName: undefined,
|
||||||
// 文章标题
|
// 网站标识
|
||||||
title: undefined,
|
websiteCode: undefined,
|
||||||
// 分类类型
|
// 网站LOGO
|
||||||
type: undefined,
|
websiteIcon: undefined,
|
||||||
// 展现方式
|
// 网站LOGO
|
||||||
showType: undefined,
|
websiteLogo: undefined,
|
||||||
// 文章类型
|
// 网站LOGO(深色模式)
|
||||||
categoryId: undefined,
|
websiteDarkLogo: undefined,
|
||||||
// 文章分类
|
// 网站类型
|
||||||
categoryName: undefined,
|
websiteType: undefined,
|
||||||
parentId: undefined,
|
// 评分
|
||||||
// 封面图
|
rate: undefined,
|
||||||
image: undefined,
|
// 点赞数
|
||||||
// 附件
|
|
||||||
files: undefined,
|
|
||||||
// 附件
|
|
||||||
fileList: [],
|
|
||||||
// 缩列图
|
|
||||||
thumbnail: undefined,
|
|
||||||
// 视频地址
|
|
||||||
video: undefined,
|
|
||||||
// 上传的文件类型
|
|
||||||
accept: undefined,
|
|
||||||
// 来源
|
|
||||||
source: undefined,
|
|
||||||
// 标签
|
|
||||||
tags: undefined,
|
|
||||||
// 文章内容
|
|
||||||
content: undefined,
|
|
||||||
// 虚拟阅读量
|
|
||||||
virtualViews: undefined,
|
|
||||||
// 实际阅读量
|
|
||||||
actualViews: undefined,
|
|
||||||
// 访问权限
|
|
||||||
permission: undefined,
|
|
||||||
// 访问密码
|
|
||||||
password: undefined,
|
|
||||||
password2: undefined,
|
|
||||||
// 用户ID
|
|
||||||
userId: undefined,
|
|
||||||
// 用户昵称
|
|
||||||
nickname: undefined,
|
|
||||||
// 账号
|
|
||||||
username: undefined,
|
|
||||||
// 用户头像
|
|
||||||
// userAvatar: undefined,
|
|
||||||
author: undefined,
|
|
||||||
// 所属门店ID
|
|
||||||
shopId: undefined,
|
|
||||||
//
|
|
||||||
likes: undefined,
|
likes: undefined,
|
||||||
// 排序
|
// 访问量
|
||||||
sortNumber: undefined,
|
clicks: undefined,
|
||||||
|
// 下载量
|
||||||
|
downloads: undefined,
|
||||||
|
// 网站截图
|
||||||
|
files: undefined,
|
||||||
|
// 网站关键词
|
||||||
|
keywords: undefined,
|
||||||
|
// 域名前缀
|
||||||
|
prefix: undefined,
|
||||||
|
// 绑定域名
|
||||||
|
domain: undefined,
|
||||||
|
// 全局样式
|
||||||
|
style: undefined,
|
||||||
|
// 后台管理地址
|
||||||
|
adminUrl: undefined,
|
||||||
|
// 应用版本 10免费版 20专业版 30永久授权
|
||||||
|
version: undefined,
|
||||||
|
// 服务到期时间
|
||||||
|
expirationTime: undefined,
|
||||||
|
// 模版ID
|
||||||
|
templateId: undefined,
|
||||||
|
// 行业类型(父级)
|
||||||
|
industryParent: undefined,
|
||||||
|
// 行业类型(子级)
|
||||||
|
industryChild: undefined,
|
||||||
|
// 企业ID
|
||||||
|
companyId: undefined,
|
||||||
|
// 所在国家
|
||||||
|
country: undefined,
|
||||||
|
// 所在省份
|
||||||
|
province: undefined,
|
||||||
|
// 所在城市
|
||||||
|
city: undefined,
|
||||||
|
// 所在辖区
|
||||||
|
region: undefined,
|
||||||
|
// 经度
|
||||||
|
longitude: undefined,
|
||||||
|
// 纬度
|
||||||
|
latitude: undefined,
|
||||||
|
// 街道地址
|
||||||
|
address: undefined,
|
||||||
|
// 联系电话
|
||||||
|
phone: undefined,
|
||||||
|
// 电子邮箱
|
||||||
|
email: undefined,
|
||||||
|
// ICP备案号
|
||||||
|
icpNo: undefined,
|
||||||
|
// 公安备案
|
||||||
|
policeNo: undefined,
|
||||||
// 备注
|
// 备注
|
||||||
comments: undefined,
|
comments: undefined,
|
||||||
// 状态
|
// 是否推荐
|
||||||
|
recommend: undefined,
|
||||||
|
// 运行状态
|
||||||
|
running: undefined,
|
||||||
|
// 状态 0未开通 1运行中 2维护中 3已关闭 4已欠费停机 5违规关停
|
||||||
status: undefined,
|
status: undefined,
|
||||||
|
// 维护说明
|
||||||
|
statusText: undefined,
|
||||||
|
// 关闭说明
|
||||||
|
statusClose: undefined,
|
||||||
|
// 状态图标
|
||||||
|
statusIcon: undefined,
|
||||||
|
// 全局样式
|
||||||
|
styles: undefined,
|
||||||
|
content: undefined,
|
||||||
|
// 排序号
|
||||||
|
sortNumber: undefined,
|
||||||
|
// 用户ID
|
||||||
|
userId: undefined,
|
||||||
|
// 是否删除, 0否, 1是
|
||||||
|
deleted: undefined,
|
||||||
|
// 租户id
|
||||||
|
tenantId: undefined,
|
||||||
// 创建时间
|
// 创建时间
|
||||||
createTime: undefined,
|
createTime: undefined,
|
||||||
// 更新时间
|
// 修改时间
|
||||||
updateTime: undefined,
|
updateTime: undefined,
|
||||||
// 租户ID
|
// 网站配置
|
||||||
tenantId: undefined,
|
config: undefined,
|
||||||
// 租户名称
|
topNavs: undefined,
|
||||||
tenantName: undefined,
|
bottomNavs: undefined,
|
||||||
// 租户logo
|
loginUser: undefined
|
||||||
logo: undefined,
|
|
||||||
// 详情页路径
|
|
||||||
detail: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
// 搜索表单
|
|
||||||
const where = reactive<CmsArticleParam>({
|
|
||||||
keywords: '',
|
|
||||||
page: 1,
|
|
||||||
limit: 20,
|
|
||||||
status: 0,
|
|
||||||
parentId: undefined,
|
|
||||||
categoryId: undefined,
|
|
||||||
lang: i18n.locale.value
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const doComments = async (page: any) => {
|
const doComments = async (page: any) => {
|
||||||
@@ -219,40 +193,37 @@ const reloadComments = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
|
||||||
// 读取导航详情
|
// 读取导航详情
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
getCmsArticle(navId.value).then(data => {
|
getCmsWebsiteAll(navId.value).then(data => {
|
||||||
// 获取栏目信息
|
// 获取栏目信息
|
||||||
page.value = data
|
|
||||||
assignFields(data)
|
assignFields(data)
|
||||||
layout.value.banner = data.banner;
|
page.value = {
|
||||||
|
image: data.websiteLogo,
|
||||||
|
title: data.websiteName,
|
||||||
|
categoryName: '应用市场',
|
||||||
|
...data,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用截图
|
||||||
|
if(data.files){
|
||||||
|
const imgArr = JSON.parse(data.files);
|
||||||
|
imgArr.map((item: any) => {
|
||||||
|
srcList.value.push(item.url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
description: data.comments || data.title,
|
description: data.comments || data.websiteName,
|
||||||
keywords: data.title,
|
keywords: data.websiteName,
|
||||||
titleTemplate: `${data?.title}` + ' - %s',
|
titleTemplate: `${data?.websiteName}` + ' - %s',
|
||||||
})
|
})
|
||||||
|
|
||||||
// 二级栏目分类
|
|
||||||
// listCmsNavigation({
|
|
||||||
// parentId: data.parentId == 0 ? data.navigationId : data.parentId
|
|
||||||
// }).then(categoryData => {
|
|
||||||
// category.value = categoryData;
|
|
||||||
// // 加载文章列表
|
|
||||||
// if(data.parentId == 0 && category.value.length > 0){
|
|
||||||
// where.parentId = data.navigationId;
|
|
||||||
// }else {
|
|
||||||
// where.categoryId = data.navigationId;
|
|
||||||
// }
|
|
||||||
// pageCmsArticle(where).then(response => {
|
|
||||||
// if(response){
|
|
||||||
// total.value = response?.count;
|
|
||||||
// list.value = response?.list;
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err,'加载失败...')
|
console.log(err,'加载失败...')
|
||||||
})
|
})
|
||||||
@@ -275,4 +246,14 @@ watch(
|
|||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scrollbar-flex-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.scrollbar-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
82
pages/item/components/AppInfo.vue
Normal file
82
pages/item/components/AppInfo.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="form" class="app-info flex justify-around items-center">
|
||||||
|
<div class="item text-center">
|
||||||
|
<div class="rate text-gray-400">评分</div>
|
||||||
|
<div class="text-2xl font-bold">3.1</div>
|
||||||
|
<el-rate v-model="form.rate" disabled size="small"/>
|
||||||
|
</div>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<div class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">插件ID</div>
|
||||||
|
<el-icon size="24" class="py-1"><Cpu /></el-icon>
|
||||||
|
<span class="text-gray-500">{{ form.websiteCode }}</span>
|
||||||
|
</div>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<nuxt-link class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">类型</div>
|
||||||
|
<el-icon size="24" class="py-1"><Monitor /></el-icon>
|
||||||
|
<span class="text-gray-500">{{ '小程序' }}</span>
|
||||||
|
</nuxt-link>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<nuxt-link :to="`https://${form.tenantId}.wsdns.cn`" class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">开发者</div>
|
||||||
|
<el-icon size="24" class="py-1"><Avatar /></el-icon>
|
||||||
|
<span class="text-gray-500">{{'WebSoft Inc.'}}</span>
|
||||||
|
</nuxt-link>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<div class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">下载次数</div>
|
||||||
|
<!-- <div>#<span class="text-2xl font-bold">13</span></div>-->
|
||||||
|
<el-icon size="24" class="py-1"><Download /></el-icon>
|
||||||
|
<span class="text-gray-500">{{ form.downloads }}</span>
|
||||||
|
</div>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<div class="item text-center">
|
||||||
|
<div class="text-gray-400">大小</div>
|
||||||
|
<div class="text-2xl font-bold">26</div>
|
||||||
|
<span class="text-gray-400">MB</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View, Menu, Search, Cpu,Monitor, Download, Platform, Avatar } from '@element-plus/icons-vue'
|
||||||
|
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
||||||
|
import {getTenantIdByDomain} from "~/api/cms/cmsDomain";
|
||||||
|
import {listTenant} from "~/api/system/tenant";
|
||||||
|
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
buyUrl?: string;
|
||||||
|
form?: CmsWebsite;
|
||||||
|
value?: number;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<any>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<el-descriptions title="评分及评价">
|
||||||
|
<template #extra>
|
||||||
|
<el-button type="text" @click="onComplaint">投诉</el-button>
|
||||||
|
<el-button type="text" @click="onComments">发表评论</el-button>
|
||||||
|
</template>
|
||||||
|
</el-descriptions>
|
||||||
<form
|
<form
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="form"
|
:model="form"
|
||||||
@@ -8,18 +14,7 @@
|
|||||||
size="large"
|
size="large"
|
||||||
status-icon
|
status-icon
|
||||||
>
|
>
|
||||||
<el-card shadow="hover" v-if="comments" class="mb-5">
|
<template v-if="comments && comments.length > 0">
|
||||||
<template #header>
|
|
||||||
<div class="card-header font-bold text-xl flex justify-between">
|
|
||||||
<span>评分和评价</span>
|
|
||||||
<div class="comments">
|
|
||||||
<el-button @click="onComplaint">投诉</el-button>
|
|
||||||
<el-button type="primary" @click="onComments">发表评论</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<template v-if="comments.length > 0">
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div v-for="(item,index) in comments" :key="index"
|
<div v-for="(item,index) in comments" :key="index"
|
||||||
class="flex flex-col border-b-2 border-gray-200 pb-2 mb-3"
|
class="flex flex-col border-b-2 border-gray-200 pb-2 mb-3"
|
||||||
@@ -54,8 +49,7 @@
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
暂无用户评论
|
暂无用户评论
|
||||||
</template>
|
</template>
|
||||||
</template>
|
|
||||||
</el-card>
|
|
||||||
<!-- 发表评论 -->
|
<!-- 发表评论 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
|
|||||||
@@ -1,54 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="banner m-auto relative sm:flex mt-15">
|
<div class="banner m-auto relative sm:flex">
|
||||||
<svg viewBox="0 0 1440 181" fill="none" xmlns="http://www.w3.org/2000/svg"
|
<div class="md:w-screen-xl m-auto py-10">
|
||||||
class="pointer-events-none absolute w-full top-[-2px] transition-all text-green-5 flex-shrink-0 opacity-100 duration-[400ms] opacity-80 -z-10">
|
|
||||||
<mask id="path-1-inside-1_414_5526" fill="white">
|
|
||||||
<path d="M0 0H1440V181H0V0Z"></path>
|
|
||||||
</mask>
|
|
||||||
<path d="M0 0H1440V181H0V0Z" fill="url(#paint0_linear_414_5526)" fill-opacity="0.22"></path>
|
|
||||||
<path d="M0 2H1440V-2H0V2Z" fill="url(#paint1_linear_414_5526)" mask="url(#path-1-inside-1_414_5526)"></path>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="paint0_linear_414_5526" x1="720" y1="0" x2="720" y2="181" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="currentColor"></stop>
|
|
||||||
<stop offset="1" stop-color="currentColor" stop-opacity="0"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="paint1_linear_414_5526" x1="0" y1="90.5" x2="1440" y2="90.5" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="currentColor" stop-opacity="0"></stop>
|
|
||||||
<stop offset="0.395" stop-color="currentColor"></stop>
|
|
||||||
<stop offset="1" stop-color="currentColor" stop-opacity="0"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
<div class="md:w-screen-xl m-auto">
|
|
||||||
<Breadcrumb :data="form" :categoryName="form?.categoryName"/>
|
|
||||||
<div class="py-8 sm:py-16" _path="/templates" _dir="" _draft="false" _partial="false" _locale=""
|
|
||||||
_id="content:4.templates.yml" _type="yaml" _source="content" _file="4.templates.yml" _stem="4.templates"
|
|
||||||
_extension="yml">
|
|
||||||
<div class="gap-8 sm:gap-y-16 lg:items-center" v-if="form">
|
<div class="gap-8 sm:gap-y-16 lg:items-center" v-if="form">
|
||||||
<div class="w-full sm:px-0 px-4">
|
<div class="w-full sm:px-0 px-4">
|
||||||
<div class="flex flex-1">
|
<div class="flex flex-1">
|
||||||
<template v-if="form.image">
|
<template v-if="form.websiteLogo">
|
||||||
<el-image :src="form.image" shape="square"
|
<el-image :src="form.websiteLogo" shape="square"
|
||||||
class="hidden-sm-and-down bg-white w-[128px] h-[128px] cursor-pointer rounded-avatar shadow-sm hover:shadow mr-4"/>
|
class="hidden-sm-and-down bg-white w-[128px] h-[128px] cursor-pointer rounded-avatar shadow-sm hover:shadow mr-6"/>
|
||||||
<!-- <el-image :src="form.image" shape="square" :size="80"-->
|
|
||||||
<!-- class="hidden-sm-and-up bg-white rounded-avatar-xs shadow-sm hover:shadow mr-4"/>-->
|
|
||||||
</template>
|
</template>
|
||||||
<div class="title flex flex-col">
|
<div class="title flex flex-col">
|
||||||
<h1
|
<h1
|
||||||
class="text-2xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-3xl lg:text-4xl">
|
class="text-2xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-3xl lg:text-3xl">
|
||||||
<span v-if="form.title">{{ form.title }}</span>
|
<span v-if="form.websiteName">{{ form.websiteName }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="my-1 text-sm text-gray-500 w-auto sm:max-w-3xl max-w-xs flex-1 dark:text-gray-400">
|
<div class="my-1 text-sm text-gray-500 w-auto sm:max-w-3xl max-w-xs flex-1 dark:text-gray-400">
|
||||||
{{ form?.comments || desc }}
|
{{ form?.comments }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <a class="company-name text-sm my-1">-->
|
<el-space class="btn">
|
||||||
<!-- {{ form.companyName || 'WebSoft Inc.' }}-->
|
<nuxt-link :to="`https://${form.websiteCode}.websoft.top`"><el-button type="primary" round>控制台</el-button></nuxt-link>
|
||||||
<!-- </a>-->
|
|
||||||
<el-rate v-model="form.rate" disabled />
|
|
||||||
<div class="btn">
|
|
||||||
<el-space class="mt-4">
|
|
||||||
<el-button>产品控制台</el-button>
|
|
||||||
<el-button>帮助文档</el-button>
|
|
||||||
</el-space>
|
</el-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,16 +25,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {FullScreen} from '@element-plus/icons-vue'
|
|
||||||
import Breadcrumb from "~/components/Breadcrumb.vue";
|
|
||||||
import type {ApiResult} from "~/api";
|
import type {ApiResult} from "~/api";
|
||||||
import type {Company} from "~/api/system/company/model";
|
import type {Company} from "~/api/system/company/model";
|
||||||
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
|
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
||||||
|
|
||||||
const token = useToken();
|
const token = useToken();
|
||||||
|
|
||||||
@@ -74,7 +39,7 @@ const props = withDefaults(
|
|||||||
title?: string;
|
title?: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
buyUrl?: string;
|
buyUrl?: string;
|
||||||
form?: CmsArticle;
|
form?: CmsWebsite;
|
||||||
value?: number;
|
value?: number;
|
||||||
}>(),
|
}>(),
|
||||||
{}
|
{}
|
||||||
@@ -95,7 +60,7 @@ const onBuy = (item: Company) => {
|
|||||||
if (!token.value || token.value == '') {
|
if (!token.value || token.value == '') {
|
||||||
ElMessage.error('请先登录');
|
ElMessage.error('请先登录');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
openSpmUrl(`/product/create`, item, item.companyId)
|
openUrl(`/product/create`, item, item.companyId)
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
45
pages/item/components/SearchBar.vue
Normal file
45
pages/item/components/SearchBar.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<el-space class="flex items-center">
|
||||||
|
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="reload"/>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Search } from '@element-plus/icons-vue'
|
||||||
|
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
|
||||||
|
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
buyUrl?: string;
|
||||||
|
form?: CmsArticle;
|
||||||
|
value?: number;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<any>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
navigateTo(`/search/${where.keywords}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
@@ -1,41 +1,26 @@
|
|||||||
<!-- 文章详情 -->
|
|
||||||
<template>
|
<template>
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 产品详情 </span>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<div class="h-[32px]"></div>
|
||||||
|
</template>
|
||||||
<PageBanner :form="page" @done="reload"/>
|
<PageBanner :form="page" @done="reload"/>
|
||||||
<div class="page-main md:w-screen-xl m-auto p-3">
|
<el-divider />
|
||||||
<el-row :gutter="24">
|
<AppInfo :form="form" />
|
||||||
<el-col :span="18" :xs="24">
|
|
||||||
<el-card shadow="hover" class="mb-5">
|
<div class="screen-item my-6">
|
||||||
<el-descriptions title="参数信息" :column="2" border>
|
<el-descriptions title="截屏" />
|
||||||
<el-descriptions-item :span="2" label="产品名称">{{page.title}}</el-descriptions-item>
|
<el-scrollbar>
|
||||||
<el-descriptions-item v-if="form.isBuy" label="租户ID"><span class="text-orange-500">{{form.title}}</span></el-descriptions-item>
|
<div class="flex" v-if="form.files">
|
||||||
<el-descriptions-item v-if="form.isBuy" label="插件ID"><span class="text-orange-500">{{form.menuId || '-'}}</span></el-descriptions-item>
|
|
||||||
<el-descriptions-item label="控制台"><a class="cursor-pointer" @click="openUrl(`https://${form.domain}`)">{{form.domain}}</a></el-descriptions-item>
|
|
||||||
<el-descriptions-item v-for="(item,index) in form.parameters" :key="index" :label="item.name">{{ item.value }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
<template v-if="form.accounts && form.accounts.length > 0">
|
|
||||||
<div class="h-[24px]"></div>
|
|
||||||
<el-descriptions title="登录账号" :column="1" border>
|
|
||||||
<template v-for="(item,index) in form.accounts" :key="index">
|
|
||||||
<el-descriptions-item :label="item.type" v-if="item.account">
|
|
||||||
还没有账号? <el-button type="text" @click="openSpmUrl(`/passport/regis`)">立即注册</el-button>
|
|
||||||
</el-descriptions-item>
|
|
||||||
</template>
|
|
||||||
</el-descriptions>
|
|
||||||
</template>
|
|
||||||
<template v-if="form.gits && form.gits.length > 0">
|
|
||||||
<div class="h-[24px]"></div>
|
|
||||||
<el-descriptions title="代码仓库" :column="1" border>
|
|
||||||
<el-descriptions-item v-for="(item,index) in form.gits" :key="index" :label="item.title">
|
|
||||||
<el-input v-model="item.domain" readonly />
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</template>
|
|
||||||
<template v-if="form.files && form.files.length > 0">
|
|
||||||
<div class="h-[24px]"></div>
|
|
||||||
<el-descriptions title="图文详情" />
|
|
||||||
<div v-for="(item,index) in JSON.parse(form.files)" :key="index" class="text item">
|
|
||||||
<el-image
|
<el-image
|
||||||
:src="item"
|
v-for="(item,index) in JSON.parse(form.files)"
|
||||||
|
:key="index"
|
||||||
|
class="scrollbar-item w-[240px] max-h-[625px] mr-4 mb-3"
|
||||||
|
:src="item.url"
|
||||||
:zoom-rate="1.2"
|
:zoom-rate="1.2"
|
||||||
:max-scale="7"
|
:max-scale="7"
|
||||||
:min-scale="0.2"
|
:min-scale="0.2"
|
||||||
@@ -44,160 +29,149 @@
|
|||||||
fit="contain"
|
fit="contain"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</el-scrollbar>
|
||||||
<template v-if="form.content">
|
<p v-html="form?.content || '介绍'" class="content"></p>
|
||||||
<p v-html="form.content" class="content"></p>
|
</div>
|
||||||
</template>
|
|
||||||
</el-card>
|
<el-divider />
|
||||||
<!-- 产品评论 -->
|
<!-- 评分及评价 -->
|
||||||
<Comments :productId="form.companyId" :comments="comments" :count="commentsTotal" @done="doComments" />
|
<Comments :productId="form.companyId" :comments="comments" :count="commentsTotal" @done="doComments" />
|
||||||
</el-col>
|
<div class="h-[100px]"></div>
|
||||||
<el-col :span="6" :xs="24">
|
</el-page-header>
|
||||||
<el-card shadow="hover" class="mb-5">
|
|
||||||
<template #header>
|
|
||||||
<div class="card-header font-bold text-xl">
|
|
||||||
<span>推荐产品</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!-- <el-space class="flex items-center">-->
|
|
||||||
<!-- <div class="avatar">-->
|
|
||||||
<!-- <el-avatar :size="55" :src="form.image"/>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="flex flex-col">-->
|
|
||||||
<!-- <span class="font-bold text-lg text-gray-600">{{ form.title }}</span>-->
|
|
||||||
<!-- <span class="text-gray-400 pb-1 line-clamp-2">{{ form.comments }}</span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </el-space>-->
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Cpu,Download,Star,Coin,Tickets} from '@element-plus/icons-vue'
|
import { ArrowLeft,View, Monitor, Search,Cpu, Platform, Avatar } from '@element-plus/icons-vue'
|
||||||
import type {ApiResult, PageResult} from "~/api";
|
import type {ApiResult, PageResult} from "~/api";
|
||||||
import {useServerRequest} from "~/composables/useServerRequest";
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
import {useLayout, usePage, useWebsite} from "~/composables/configState";
|
import {usePage} from "~/composables/configState";
|
||||||
import type {BreadcrumbItem} from "~/types/global";
|
|
||||||
import {getIdBySpm, getNavIdByParamsId, openUrl} from "~/utils/common";
|
import {getIdBySpm, getNavIdByParamsId, openUrl} from "~/utils/common";
|
||||||
import useFormData from "~/utils/use-form-data";
|
import useFormData from "~/utils/use-form-data";
|
||||||
import PageBanner from './components/PageBanner.vue';
|
import PageBanner from './components/PageBanner.vue';
|
||||||
|
import AppInfo from './components/AppInfo.vue';
|
||||||
import Comments from './components/Comments.vue';
|
import Comments from './components/Comments.vue';
|
||||||
import type {Company} from "~/api/system/company/model";
|
|
||||||
import type {CompanyComment} from "~/api/system/companyComment/model";
|
import type {CompanyComment} from "~/api/system/companyComment/model";
|
||||||
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
import {getCmsWebsiteAll} from "~/api/cms/cmsWebsite";
|
||||||
import {getCmsArticle, pageCmsArticle} from "~/api/cms/cmsArticle";
|
|
||||||
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
|
||||||
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
|
||||||
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
||||||
import {getCmsWebsite} from "~/api/cms/cmsWebsite";
|
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
||||||
|
import Banner from "~/components/Banner.vue";
|
||||||
|
|
||||||
// 引入状态管理
|
// 引入状态管理
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const page = usePage();
|
const page = usePage();
|
||||||
const layout = useLayout();
|
|
||||||
const category = ref<CmsNavigation[]>([]);
|
|
||||||
const i18n = useI18n();
|
|
||||||
const total = ref(0);
|
|
||||||
const list = ref<CmsArticle[]>([]);
|
|
||||||
const website = useWebsite();
|
|
||||||
const breadcrumb = ref<BreadcrumbItem>();
|
|
||||||
const comments = ref<CompanyComment[]>([]);
|
const comments = ref<CompanyComment[]>([]);
|
||||||
const commentsTotal = ref(0);
|
const commentsTotal = ref(0);
|
||||||
const commentsPage = ref(1);
|
const commentsPage = ref(1);
|
||||||
const navId = ref();
|
const navId = ref();
|
||||||
const activeName = ref();
|
|
||||||
const url =
|
|
||||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
|
|
||||||
const srcList = ref<any[]>([]);
|
const srcList = ref<any[]>([]);
|
||||||
|
|
||||||
// 配置信息
|
// 配置信息
|
||||||
const {form, assignFields} = useFormData<CmsWebsite>({
|
const {form, assignFields} = useFormData<CmsWebsite>({
|
||||||
// 文章id
|
// 站点ID
|
||||||
articleId: undefined,
|
websiteId: undefined,
|
||||||
// 文章模型
|
// 网站名称
|
||||||
model: undefined,
|
websiteName: undefined,
|
||||||
// 文章标题
|
// 网站标识
|
||||||
title: undefined,
|
websiteCode: undefined,
|
||||||
// 分类类型
|
// 网站LOGO
|
||||||
type: undefined,
|
websiteIcon: undefined,
|
||||||
// 展现方式
|
// 网站LOGO
|
||||||
showType: undefined,
|
websiteLogo: undefined,
|
||||||
// 文章类型
|
// 网站LOGO(深色模式)
|
||||||
categoryId: undefined,
|
websiteDarkLogo: undefined,
|
||||||
// 文章分类
|
// 网站类型
|
||||||
categoryName: undefined,
|
websiteType: undefined,
|
||||||
parentId: undefined,
|
// 评分
|
||||||
// 封面图
|
rate: undefined,
|
||||||
image: undefined,
|
// 点赞数
|
||||||
// 附件
|
|
||||||
files: undefined,
|
|
||||||
// 附件
|
|
||||||
fileList: [],
|
|
||||||
// 缩列图
|
|
||||||
thumbnail: undefined,
|
|
||||||
// 视频地址
|
|
||||||
video: undefined,
|
|
||||||
// 上传的文件类型
|
|
||||||
accept: undefined,
|
|
||||||
// 来源
|
|
||||||
source: undefined,
|
|
||||||
// 标签
|
|
||||||
tags: undefined,
|
|
||||||
// 文章内容
|
|
||||||
content: undefined,
|
|
||||||
// 虚拟阅读量
|
|
||||||
virtualViews: undefined,
|
|
||||||
// 实际阅读量
|
|
||||||
actualViews: undefined,
|
|
||||||
// 访问权限
|
|
||||||
permission: undefined,
|
|
||||||
// 访问密码
|
|
||||||
password: undefined,
|
|
||||||
password2: undefined,
|
|
||||||
// 用户ID
|
|
||||||
userId: undefined,
|
|
||||||
// 用户昵称
|
|
||||||
nickname: undefined,
|
|
||||||
// 账号
|
|
||||||
username: undefined,
|
|
||||||
// 用户头像
|
|
||||||
// userAvatar: undefined,
|
|
||||||
author: undefined,
|
|
||||||
// 所属门店ID
|
|
||||||
shopId: undefined,
|
|
||||||
//
|
|
||||||
likes: undefined,
|
likes: undefined,
|
||||||
// 排序
|
// 访问量
|
||||||
sortNumber: undefined,
|
clicks: undefined,
|
||||||
|
// 下载量
|
||||||
|
downloads: undefined,
|
||||||
|
// 网站截图
|
||||||
|
files: undefined,
|
||||||
|
// 网站关键词
|
||||||
|
keywords: undefined,
|
||||||
|
// 域名前缀
|
||||||
|
prefix: undefined,
|
||||||
|
// 绑定域名
|
||||||
|
domain: undefined,
|
||||||
|
// 全局样式
|
||||||
|
style: undefined,
|
||||||
|
// 后台管理地址
|
||||||
|
adminUrl: undefined,
|
||||||
|
// 应用版本 10免费版 20专业版 30永久授权
|
||||||
|
version: undefined,
|
||||||
|
// 服务到期时间
|
||||||
|
expirationTime: undefined,
|
||||||
|
// 模版ID
|
||||||
|
templateId: undefined,
|
||||||
|
// 行业类型(父级)
|
||||||
|
industryParent: undefined,
|
||||||
|
// 行业类型(子级)
|
||||||
|
industryChild: undefined,
|
||||||
|
// 企业ID
|
||||||
|
companyId: undefined,
|
||||||
|
// 所在国家
|
||||||
|
country: undefined,
|
||||||
|
// 所在省份
|
||||||
|
province: undefined,
|
||||||
|
// 所在城市
|
||||||
|
city: undefined,
|
||||||
|
// 所在辖区
|
||||||
|
region: undefined,
|
||||||
|
// 经度
|
||||||
|
longitude: undefined,
|
||||||
|
// 纬度
|
||||||
|
latitude: undefined,
|
||||||
|
// 街道地址
|
||||||
|
address: undefined,
|
||||||
|
// 联系电话
|
||||||
|
phone: undefined,
|
||||||
|
// 电子邮箱
|
||||||
|
email: undefined,
|
||||||
|
// ICP备案号
|
||||||
|
icpNo: undefined,
|
||||||
|
// 公安备案
|
||||||
|
policeNo: undefined,
|
||||||
// 备注
|
// 备注
|
||||||
comments: undefined,
|
comments: undefined,
|
||||||
// 状态
|
// 是否推荐
|
||||||
|
recommend: undefined,
|
||||||
|
// 运行状态
|
||||||
|
running: undefined,
|
||||||
|
// 状态 0未开通 1运行中 2维护中 3已关闭 4已欠费停机 5违规关停
|
||||||
status: undefined,
|
status: undefined,
|
||||||
|
// 维护说明
|
||||||
|
statusText: undefined,
|
||||||
|
// 关闭说明
|
||||||
|
statusClose: undefined,
|
||||||
|
// 状态图标
|
||||||
|
statusIcon: undefined,
|
||||||
|
// 全局样式
|
||||||
|
styles: undefined,
|
||||||
|
content: undefined,
|
||||||
|
// 排序号
|
||||||
|
sortNumber: undefined,
|
||||||
|
// 用户ID
|
||||||
|
userId: undefined,
|
||||||
|
// 是否删除, 0否, 1是
|
||||||
|
deleted: undefined,
|
||||||
|
// 租户id
|
||||||
|
tenantId: undefined,
|
||||||
// 创建时间
|
// 创建时间
|
||||||
createTime: undefined,
|
createTime: undefined,
|
||||||
// 更新时间
|
// 修改时间
|
||||||
updateTime: undefined,
|
updateTime: undefined,
|
||||||
// 租户ID
|
// 网站配置
|
||||||
tenantId: undefined,
|
config: undefined,
|
||||||
// 租户名称
|
topNavs: undefined,
|
||||||
tenantName: undefined,
|
bottomNavs: undefined,
|
||||||
// 租户logo
|
loginUser: undefined
|
||||||
logo: undefined,
|
|
||||||
// 详情页路径
|
|
||||||
detail: undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
// 搜索表单
|
|
||||||
const where = reactive<CmsArticleParam>({
|
|
||||||
keywords: '',
|
|
||||||
page: 1,
|
|
||||||
limit: 20,
|
|
||||||
status: 0,
|
|
||||||
parentId: undefined,
|
|
||||||
categoryId: undefined,
|
|
||||||
lang: i18n.locale.value
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const doComments = async (page: any) => {
|
const doComments = async (page: any) => {
|
||||||
@@ -221,9 +195,13 @@ const reloadComments = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
|
||||||
// 读取导航详情
|
// 读取导航详情
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
getCmsWebsite(navId.value).then(data => {
|
getCmsWebsiteAll(navId.value).then(data => {
|
||||||
// 获取栏目信息
|
// 获取栏目信息
|
||||||
assignFields(data)
|
assignFields(data)
|
||||||
page.value = {
|
page.value = {
|
||||||
@@ -233,6 +211,14 @@ const reload = async () => {
|
|||||||
...data,
|
...data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 应用截图
|
||||||
|
if(data.files){
|
||||||
|
const imgArr = JSON.parse(data.files);
|
||||||
|
imgArr.map((item: any) => {
|
||||||
|
srcList.value.push(item.url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 设置页面标题
|
// 设置页面标题
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
description: data.comments || data.websiteName,
|
description: data.comments || data.websiteName,
|
||||||
@@ -240,25 +226,6 @@ const reload = async () => {
|
|||||||
titleTemplate: `${data?.websiteName}` + ' - %s',
|
titleTemplate: `${data?.websiteName}` + ' - %s',
|
||||||
})
|
})
|
||||||
|
|
||||||
// 二级栏目分类
|
|
||||||
// listCmsNavigation({
|
|
||||||
// parentId: data.parentId == 0 ? data.navigationId : data.parentId
|
|
||||||
// }).then(categoryData => {
|
|
||||||
// category.value = categoryData;
|
|
||||||
// // 加载文章列表
|
|
||||||
// if(data.parentId == 0 && category.value.length > 0){
|
|
||||||
// where.parentId = data.navigationId;
|
|
||||||
// }else {
|
|
||||||
// where.categoryId = data.navigationId;
|
|
||||||
// }
|
|
||||||
// pageCmsArticle(where).then(response => {
|
|
||||||
// if(response){
|
|
||||||
// total.value = response?.count;
|
|
||||||
// list.value = response?.list;
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err,'加载失败...')
|
console.log(err,'加载失败...')
|
||||||
})
|
})
|
||||||
@@ -281,4 +248,14 @@ watch(
|
|||||||
height: auto !important;
|
height: auto !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.scrollbar-flex-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.scrollbar-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
82
pages/market/components/AppInfo.vue
Normal file
82
pages/market/components/AppInfo.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="form" class="app-info flex justify-around items-center">
|
||||||
|
<div class="item text-center">
|
||||||
|
<div class="rate text-gray-400">评分</div>
|
||||||
|
<div class="text-2xl font-bold">3.1</div>
|
||||||
|
<el-rate v-model="form.rate" disabled size="small"/>
|
||||||
|
</div>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<div class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">插件ID</div>
|
||||||
|
<el-icon size="24" class="py-1"><Cpu /></el-icon>
|
||||||
|
<span class="text-gray-500">{{ form.websiteCode }}</span>
|
||||||
|
</div>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<nuxt-link class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">类型</div>
|
||||||
|
<el-icon size="24" class="py-1"><Monitor /></el-icon>
|
||||||
|
<span class="text-gray-500">{{ '小程序' }}</span>
|
||||||
|
</nuxt-link>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<nuxt-link :to="`https://${form.tenantId}.wsdns.cn`" class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">开发者</div>
|
||||||
|
<el-icon size="24" class="py-1"><Avatar /></el-icon>
|
||||||
|
<span class="text-gray-500">{{'WebSoft Inc.'}}</span>
|
||||||
|
</nuxt-link>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<div class="item text-center flex flex-col items-center">
|
||||||
|
<div class="text-gray-400">下载次数</div>
|
||||||
|
<!-- <div>#<span class="text-2xl font-bold">13</span></div>-->
|
||||||
|
<el-icon size="24" class="py-1"><Download /></el-icon>
|
||||||
|
<span class="text-gray-500">{{ form.downloads }}</span>
|
||||||
|
</div>
|
||||||
|
<el-divider class="opacity-40" style="height: 40px" direction="vertical" />
|
||||||
|
<div class="item text-center">
|
||||||
|
<div class="text-gray-400">大小</div>
|
||||||
|
<div class="text-2xl font-bold">26</div>
|
||||||
|
<span class="text-gray-400">MB</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View, Menu, Search, Cpu,Monitor, Download, Platform, Avatar } from '@element-plus/icons-vue'
|
||||||
|
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
||||||
|
import {getTenantIdByDomain} from "~/api/cms/cmsDomain";
|
||||||
|
import {listTenant} from "~/api/system/tenant";
|
||||||
|
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
buyUrl?: string;
|
||||||
|
form?: CmsWebsite;
|
||||||
|
value?: number;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<any>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<el-descriptions title="评分及评价">
|
||||||
|
<template #extra>
|
||||||
|
<el-button type="text" @click="onComplaint">投诉</el-button>
|
||||||
|
<el-button type="text" @click="onComments">发表评论</el-button>
|
||||||
|
</template>
|
||||||
|
</el-descriptions>
|
||||||
<form
|
<form
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="form"
|
:model="form"
|
||||||
@@ -8,18 +14,7 @@
|
|||||||
size="large"
|
size="large"
|
||||||
status-icon
|
status-icon
|
||||||
>
|
>
|
||||||
<el-card shadow="hover" v-if="comments" class="mb-5">
|
<template v-if="comments && comments.length > 0">
|
||||||
<template #header>
|
|
||||||
<div class="card-header font-bold text-xl flex justify-between">
|
|
||||||
<span>评分和评价</span>
|
|
||||||
<div class="comments">
|
|
||||||
<el-button @click="onComplaint">投诉</el-button>
|
|
||||||
<el-button type="primary" @click="onComments">发表评论</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<template v-if="comments.length > 0">
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div v-for="(item,index) in comments" :key="index"
|
<div v-for="(item,index) in comments" :key="index"
|
||||||
class="flex flex-col border-b-2 border-gray-200 pb-2 mb-3"
|
class="flex flex-col border-b-2 border-gray-200 pb-2 mb-3"
|
||||||
@@ -54,8 +49,7 @@
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
暂无用户评论
|
暂无用户评论
|
||||||
</template>
|
</template>
|
||||||
</template>
|
|
||||||
</el-card>
|
|
||||||
<!-- 发表评论 -->
|
<!-- 发表评论 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
|
|||||||
@@ -1,71 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="banner m-auto relative sm:flex mt-15">
|
<div class="banner m-auto relative sm:flex">
|
||||||
<svg viewBox="0 0 1440 181" fill="none" xmlns="http://www.w3.org/2000/svg"
|
<div class="md:w-screen-xl m-auto py-10">
|
||||||
class="pointer-events-none absolute w-full top-[-2px] transition-all text-green-5 flex-shrink-0 opacity-100 duration-[400ms] opacity-80 -z-10">
|
|
||||||
<mask id="path-1-inside-1_414_5526" fill="white">
|
|
||||||
<path d="M0 0H1440V181H0V0Z"></path>
|
|
||||||
</mask>
|
|
||||||
<path d="M0 0H1440V181H0V0Z" fill="url(#paint0_linear_414_5526)" fill-opacity="0.22"></path>
|
|
||||||
<path d="M0 2H1440V-2H0V2Z" fill="url(#paint1_linear_414_5526)" mask="url(#path-1-inside-1_414_5526)"></path>
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="paint0_linear_414_5526" x1="720" y1="0" x2="720" y2="181" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="currentColor"></stop>
|
|
||||||
<stop offset="1" stop-color="currentColor" stop-opacity="0"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="paint1_linear_414_5526" x1="0" y1="90.5" x2="1440" y2="90.5" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="currentColor" stop-opacity="0"></stop>
|
|
||||||
<stop offset="0.395" stop-color="currentColor"></stop>
|
|
||||||
<stop offset="1" stop-color="currentColor" stop-opacity="0"></stop>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
<div class="md:w-screen-xl m-auto">
|
|
||||||
<Breadcrumb :data="form" :categoryName="form?.categoryName"/>
|
|
||||||
<div class="py-8 sm:py-16" _path="/templates" _dir="" _draft="false" _partial="false" _locale=""
|
|
||||||
_id="content:4.templates.yml" _type="yaml" _source="content" _file="4.templates.yml" _stem="4.templates"
|
|
||||||
_extension="yml">
|
|
||||||
<div class="gap-8 sm:gap-y-16 lg:items-center" v-if="form">
|
<div class="gap-8 sm:gap-y-16 lg:items-center" v-if="form">
|
||||||
<div class="w-full sm:px-0 px-4">
|
<div class="w-full sm:px-0 px-4">
|
||||||
<div class="flex flex-1">
|
<div class="flex flex-1">
|
||||||
<template v-if="form.image">
|
<template v-if="form.websiteLogo">
|
||||||
<el-image :src="form.image" shape="square"
|
<el-image :src="form.websiteLogo" shape="square"
|
||||||
class="hidden-sm-and-down bg-white w-[128px] h-[128px] cursor-pointer rounded-avatar shadow-sm hover:shadow mr-4"/>
|
class="hidden-sm-and-down bg-white w-[128px] h-[128px] cursor-pointer rounded-avatar shadow-sm hover:shadow mr-6"/>
|
||||||
<!-- <el-image :src="form.image" shape="square" :size="80"-->
|
|
||||||
<!-- class="hidden-sm-and-up bg-white rounded-avatar-xs shadow-sm hover:shadow mr-4"/>-->
|
|
||||||
</template>
|
</template>
|
||||||
<div class="title flex flex-col">
|
<div class="title flex flex-col">
|
||||||
<h1
|
<h1
|
||||||
class="text-2xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-3xl lg:text-4xl">
|
class="text-2xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-3xl lg:text-3xl">
|
||||||
<span v-if="form.title">{{ form.title }}</span>
|
<el-space>
|
||||||
|
<span>{{ form.websiteName }}</span>
|
||||||
|
</el-space>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="my-1 text-sm text-gray-500 w-auto sm:max-w-3xl max-w-xs flex-1 dark:text-gray-400">
|
<div class="my-1 text-sm text-gray-500 w-auto sm:max-w-3xl max-w-xs flex-1 dark:text-gray-400">
|
||||||
{{ form?.comments || desc }}
|
{{ form?.comments || desc }}
|
||||||
</div>
|
</div>
|
||||||
<!-- <a class="company-name text-sm my-1">-->
|
<el-space class="btn">
|
||||||
<!-- {{ form.companyName || 'WebSoft Inc.' }}-->
|
<nuxt-link target="_blank"><el-button type="primary" round>获取</el-button></nuxt-link>
|
||||||
<!-- </a>-->
|
|
||||||
<el-rate v-model="form.rate" disabled />
|
|
||||||
<div class="btn">
|
|
||||||
<el-space class="mt-4">
|
|
||||||
<el-button>产品控制台</el-button>
|
|
||||||
<el-button>帮助文档</el-button>
|
|
||||||
</el-space>
|
</el-space>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!-- {{ form }}-->
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {FullScreen} from '@element-plus/icons-vue'
|
|
||||||
import Breadcrumb from "~/components/Breadcrumb.vue";
|
|
||||||
import type {ApiResult} from "~/api";
|
import type {ApiResult} from "~/api";
|
||||||
import type {Company} from "~/api/system/company/model";
|
import type {Company} from "~/api/system/company/model";
|
||||||
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
|
import type {CmsWebsite} from "~/api/cms/cmsWebsite/model";
|
||||||
|
|
||||||
const token = useToken();
|
const token = useToken();
|
||||||
|
|
||||||
@@ -74,7 +42,7 @@ const props = withDefaults(
|
|||||||
title?: string;
|
title?: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
buyUrl?: string;
|
buyUrl?: string;
|
||||||
form?: CmsArticle;
|
form?: CmsWebsite;
|
||||||
value?: number;
|
value?: number;
|
||||||
}>(),
|
}>(),
|
||||||
{}
|
{}
|
||||||
@@ -95,7 +63,7 @@ const onBuy = (item: Company) => {
|
|||||||
if (!token.value || token.value == '') {
|
if (!token.value || token.value == '') {
|
||||||
ElMessage.error('请先登录');
|
ElMessage.error('请先登录');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
openSpmUrl(`/product/create`, item, item.companyId)
|
navigateTo(`/product/create`)
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
45
pages/market/components/SearchBar.vue
Normal file
45
pages/market/components/SearchBar.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<el-space class="flex items-center">
|
||||||
|
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="reload"/>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Search } from '@element-plus/icons-vue'
|
||||||
|
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
|
||||||
|
|
||||||
|
const i18n = useI18n();
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
buyUrl?: string;
|
||||||
|
form?: CmsArticle;
|
||||||
|
value?: number;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<any>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
navigateTo(`/search/${where.keywords}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
<!-- :value="item.value"-->
|
<!-- :value="item.value"-->
|
||||||
<!-- />-->
|
<!-- />-->
|
||||||
<!-- </el-select>-->
|
<!-- </el-select>-->
|
||||||
<el-button-group>
|
<el-input v-model="where.keywords" style="width: 400px" :placeholder="`应用搜索`" :suffix-icon="Search" @change="reload"/>
|
||||||
|
<el-button-group v-model:value="where" @tab-click="handleClick" @change="reload">
|
||||||
|
<el-button>综合</el-button>
|
||||||
<el-button>最新</el-button>
|
<el-button>最新</el-button>
|
||||||
<el-button>免费</el-button>
|
<el-button>免费</el-button>
|
||||||
<el-button>付费</el-button>
|
<el-button>付费</el-button>
|
||||||
<el-button>综合</el-button>
|
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="reload"/>
|
|
||||||
</el-space>
|
</el-space>
|
||||||
</template>
|
</template>
|
||||||
<el-row :gutter="24" id="container" class="clearfix">
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-image pt-3">
|
<div class="item-image pt-3">
|
||||||
<el-image v-if="item.files" :src="`${JSON.parse(item.files)[0].url}`" class="w-full h-1/2" />
|
<el-image v-if="item.files" :src="`${JSON.parse(item.files)[0].url}`" class="w-full h-1/2 max-h-[220px]" />
|
||||||
<el-image v-else class="w-full h-[220px]" />
|
<el-image v-else class="w-full h-[220px]" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,10 +89,11 @@ const layout = useLayout();
|
|||||||
const where = reactive<CmsWebsiteParam>({
|
const where = reactive<CmsWebsiteParam>({
|
||||||
keywords: '',
|
keywords: '',
|
||||||
page: 1,
|
page: 1,
|
||||||
limit: 20,
|
limit: 12,
|
||||||
status: 0,
|
status: undefined,
|
||||||
|
recommend: undefined,
|
||||||
categoryId: undefined,
|
categoryId: undefined,
|
||||||
lang: i18n.locale.value
|
lang: undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
|
|||||||
201
pages/market/search.vue
Normal file
201
pages/market/search.vue
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 应用市场 </span>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<el-space class="flex items-center">
|
||||||
|
<!-- <el-select v-model="value" clearable placeholder="筛选" style="width: 240px">-->
|
||||||
|
<!-- <el-option-->
|
||||||
|
<!-- v-for="item in options"-->
|
||||||
|
<!-- :key="item.value"-->
|
||||||
|
<!-- :label="item.label"-->
|
||||||
|
<!-- :value="item.value"-->
|
||||||
|
<!-- />-->
|
||||||
|
<!-- </el-select>-->
|
||||||
|
<el-button-group>
|
||||||
|
<el-button>最新</el-button>
|
||||||
|
<el-button>免费</el-button>
|
||||||
|
<el-button>付费</el-button>
|
||||||
|
<el-button>综合</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
<el-input v-model="where.keywords" :placeholder="`${$t('searchKeywords')}...`" :suffix-icon="Search" @change="reload"/>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
|
<el-col v-for="(item,index) in list" :key="index" :span="8" class="left mb-8">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer" @click="navigateTo(`/item/${item.websiteId}.html`)">
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-4 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex gap-1.5">
|
||||||
|
<el-avatar
|
||||||
|
:src="item.websiteLogo" shape="square" :size="55" style="background-color: white;"/>
|
||||||
|
<div class="flex-1 text-lg cursor-pointer flex flex-col">
|
||||||
|
{{ item.websiteName }}
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<sapn class="text-xs text-gray-400 font-normal line-clamp-1">{{ item.comments || '暂无描述' }}</sapn>
|
||||||
|
<el-button size="small" round>获取</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-image pt-3">
|
||||||
|
<el-image v-if="item.files" :src="`${JSON.parse(item.files)[0].url}`" class="w-full h-1/2 max-h-[220px]" />
|
||||||
|
<el-image v-else class="w-full h-[220px]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-page-header>
|
||||||
|
|
||||||
|
<Pagination :total="total" @done="search" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import { Picture as IconPicture } from '@element-plus/icons-vue'
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import { ElNotification as notify } from 'element-plus'
|
||||||
|
import { useLayout, usePage} from "~/composables/configState";
|
||||||
|
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
||||||
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
|
import type { ComponentSize } from 'element-plus'
|
||||||
|
import { ElNotification } from 'element-plus'
|
||||||
|
import type { TabsPaneContext } from 'element-plus'
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
||||||
|
import {pageCmsArticle} from "~/api/cms/cmsArticle";
|
||||||
|
import {pageCmsWebsiteAll} from "~/api/cms/cmsWebsite";
|
||||||
|
import type {CmsWebsite, CmsWebsiteParam} from "~/api/cms/cmsWebsite/model";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const navId = ref();
|
||||||
|
// 页面信息
|
||||||
|
const list = ref<CmsWebsite[]>([]);
|
||||||
|
const i18n = useI18n();
|
||||||
|
const category = ref<CmsNavigation[]>([]);
|
||||||
|
const total = ref(0);
|
||||||
|
const activeName = ref('2839');
|
||||||
|
|
||||||
|
// 获取状态
|
||||||
|
const page = usePage();
|
||||||
|
const layout = useLayout();
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<CmsWebsiteParam>({
|
||||||
|
keywords: '',
|
||||||
|
page: 1,
|
||||||
|
limit: 20,
|
||||||
|
status: 0,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载页面数据
|
||||||
|
const reload = async () => {
|
||||||
|
await pageCmsWebsiteAll(where).then(response => {
|
||||||
|
if(response?.list){
|
||||||
|
list.value = response?.list;
|
||||||
|
total.value = response.count;
|
||||||
|
}
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const bakReload = async () => {
|
||||||
|
await getCmsNavigation(navId.value).then(data => {
|
||||||
|
page.value = data;
|
||||||
|
layout.value.banner = data.banner;
|
||||||
|
|
||||||
|
// seo
|
||||||
|
useSeoMeta({
|
||||||
|
description: data.comments || data.title,
|
||||||
|
keywords: data.title,
|
||||||
|
titleTemplate: `${data?.title}` + ' - %s',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 二级栏目分类
|
||||||
|
listCmsNavigation({
|
||||||
|
parentId: data.parentId == 0 ? data.navigationId : data.parentId
|
||||||
|
}).then(navigation => {
|
||||||
|
category.value = navigation;
|
||||||
|
// 加载文章列表
|
||||||
|
if(data.parentId == 0 && category.value.length > 0){
|
||||||
|
where.parentId = page.value.navigationId;
|
||||||
|
}else {
|
||||||
|
where.categoryId = page.value.navigationId;
|
||||||
|
}
|
||||||
|
pageCmsArticle(where).then(response => {
|
||||||
|
if(response){
|
||||||
|
total.value = response.count;
|
||||||
|
list.value = response.list;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).catch(() => {})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const search = (data: CmsArticleParam) => {
|
||||||
|
where.page = data.page;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||||
|
console.log(tab, event)
|
||||||
|
}
|
||||||
|
const value = ref('')
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: 'Option1',
|
||||||
|
label: 'Option1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option2',
|
||||||
|
label: 'Option2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option3',
|
||||||
|
label: 'Option3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option4',
|
||||||
|
label: 'Option4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'Option5',
|
||||||
|
label: 'Option5',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(id) => {
|
||||||
|
// navId.value = getNavIdByParamsId(id);
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.right .content img{
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
.demo-tabs > .el-tabs__content {
|
||||||
|
padding: 32px;
|
||||||
|
color: #6b778c;
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,8 +8,14 @@
|
|||||||
<span class="text-large font-600 mr-3"> {{ page.title }} </span>
|
<span class="text-large font-600 mr-3"> {{ page.title }} </span>
|
||||||
</template>
|
</template>
|
||||||
<el-card shadow="hover" class=" my-5">
|
<el-card shadow="hover" class=" my-5">
|
||||||
|
|
||||||
|
<!-- 新闻详细 -->
|
||||||
|
<div class=" bg-white">
|
||||||
<!-- 内容组件 -->
|
<!-- 内容组件 -->
|
||||||
<Content class="content bg-white mt-5" :data="page.design?.content" />
|
<Content class="content text-lg py-3" :data="page.design?.content" />
|
||||||
|
|
||||||
|
<h3 class="tag">{{ $t('articleUrl') }}:{{ locationUrl() }} </h3>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-page-header>
|
</el-page-header>
|
||||||
</div>
|
</div>
|
||||||
@@ -18,11 +24,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {useLayout, usePage} from "~/composables/configState";
|
import {useLayout, usePage} from "~/composables/configState";
|
||||||
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
||||||
import {getNavIdByParamsId, getViews, paramsId} from "~/utils/common";
|
import {getNavIdByParamsId, getViews, locationUrl, paramsId} from "~/utils/common";
|
||||||
import Left from "~/components/Left.vue";
|
import Left from "~/components/Left.vue";
|
||||||
import { ArrowLeft,View } from '@element-plus/icons-vue'
|
import { ArrowLeft,View } from '@element-plus/icons-vue'
|
||||||
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
|
||||||
import Content from "~/components/Content.vue";
|
import Content from "~/components/Content.vue";
|
||||||
|
import Tags from "~/components/Tags.vue";
|
||||||
|
|
||||||
// 引入状态管理
|
// 引入状态管理
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|||||||
@@ -3,24 +3,21 @@
|
|||||||
<div class="flash">
|
<div class="flash">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-card class="m-5 w-screen-sm sm:w-[430px] sm:h-[520px] flex justify-around relative border-0" style="border: 0;">
|
<el-card class="m-5 w-screen-sm sm:w-[420px] sm:h-[450px] flex justify-around relative border-0" style="border: 0;">
|
||||||
<div class="login-bar absolute top-0 right-0 cursor-pointer" @click="onLoginBar">
|
<div class="login-bar absolute top-0 right-0 cursor-pointer">
|
||||||
<div class="go-to-register cursor-pointer">
|
<div class="go-to-register cursor-pointer">
|
||||||
<img src="https://img.alicdn.com/imgextra/i3/O1CN01yz6fEl1MwaRtkJyvf_!!6000000001499-55-tps-70-70.svg" alt=""/>
|
<img src="/assets/images/O1CN01yz6fEl1MwaRtkJyvf_!!6000000001499-55-tps-70-70.svg" alt=""/>
|
||||||
</div>
|
</div>
|
||||||
<span class="absolute top-3 right-1.5 text-sm text-white font-bold cursor-pointer">{{ loginBar ? '注册' : '登录' }}</span>
|
<span class="absolute top-3.5 right-2 text-sm text-white font-bold cursor-pointer"><el-icon size="20"><FullScreen /></el-icon></span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 登录界面 -->
|
<!-- 登录界面 -->
|
||||||
<el-space class="tabs pt-5 text-xl flex justify-center" v-if="loginBar">
|
<el-space class="tabs pt-3 text-xl flex justify-center" v-if="loginBar">
|
||||||
<el-tabs v-model="activeName" class="demo-tabs ">
|
<el-tabs v-model="activeName" class="">
|
||||||
<el-tab-pane label="账号登录" name="account">
|
<el-tab-pane label="密码登录" name="account">
|
||||||
<div class="custom-style my-4">
|
<div class="custom-style my-4">
|
||||||
<el-form :model="form" label-width="auto" class="w-[330px]">
|
<el-form :model="form" label-width="auto" class="w-[330px]">
|
||||||
<!-- <el-form-item>-->
|
|
||||||
<!-- <el-input class="w-full" size="large" placeholder="租户ID" :prefix-icon="Shop" v-model="form.tenantId" />-->
|
|
||||||
<!-- </el-form-item>-->
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-input class="w-full" size="large" placeholder="登录账号" :prefix-icon="Avatar" v-model="form.username" />
|
<el-input class="w-full" size="large" placeholder="登录账号" maxlength="20" :prefix-icon="Avatar" v-model="form.username" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-input type="password" size="large" maxlength="100" placeholder="登录密码" :prefix-icon="Briefcase" v-model="form.password" />
|
<el-input type="password" size="large" maxlength="100" placeholder="登录密码" :prefix-icon="Briefcase" v-model="form.password" />
|
||||||
@@ -67,20 +64,15 @@
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-space>
|
</el-space>
|
||||||
<!-- 快捷登录 --->
|
<!-- 快捷登录 --->
|
||||||
<template v-if="loginBar && activeName == 'account'">
|
<template v-if="loginBar">
|
||||||
<!-- <div class="clearfix flex justify-center">-->
|
<div class="clearfix flex justify-center">
|
||||||
<!-- <el-divider>-->
|
<nuxt-link to="/passport/login?type=register"><span class="text-sm text-blue-400">免费注册</span></nuxt-link>
|
||||||
<!-- <span class="text-gray-400">其他登录方式</span>-->
|
</div>
|
||||||
<!-- </el-divider>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="clearfix flex justify-center">-->
|
|
||||||
<!-- <el-button circle :icon="ElIconUserFilled"></el-button>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
</template>
|
</template>
|
||||||
<!-- 注册界面 -->
|
<!-- 注册界面 -->
|
||||||
<el-space class="tabs pt-5 text-xl flex justify-center" v-if="!loginBar">
|
<el-space class="tabs pt-3 text-xl flex justify-center" v-if="!loginBar">
|
||||||
<el-tabs v-model="activeName" class="demo-tabs ">
|
<el-tabs v-model="activeName">
|
||||||
<el-tab-pane label="手机号注册" name="sms">
|
<el-tab-pane label="手机号注册" name="account">
|
||||||
<span class="text-sm text-gray-400">
|
<span class="text-sm text-gray-400">
|
||||||
未注册手机号验证通过后将自动注册
|
未注册手机号验证通过后将自动注册
|
||||||
</span>
|
</span>
|
||||||
@@ -104,46 +96,13 @@
|
|||||||
<el-checkbox v-model="form.isAgree">我已阅读并同意</el-checkbox>
|
<el-checkbox v-model="form.isAgree">我已阅读并同意</el-checkbox>
|
||||||
<a href="#" class="text-gray-700">《用户协议》</a>
|
<a href="#" class="text-gray-700">《用户协议》</a>
|
||||||
<a href="#" class="text-gray-700">《隐私政策》</a>
|
<a href="#" class="text-gray-700">《隐私政策》</a>
|
||||||
<a href="#" class="text-gray-700">《产品服务协议》</a>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" size="large" class="w-full" :disabled="!form.isAgree" @click="onRegister">注册</el-button>
|
<el-button type="primary" size="large" class="w-full" :disabled="!form.isAgree" @click="onRegister">注册</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
<div class="clearfix flex justify-center">
|
||||||
|
<nuxt-link to="/passport/login"><span class="text-sm text-blue-400">已有账号,立即登录</span></nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
|
||||||
<el-tab-pane label="账号密码注册" name="account">
|
|
||||||
<div class="custom-style my-4">
|
|
||||||
<el-form :model="form" label-width="auto" class="w-[330px]">
|
|
||||||
<el-form-item>
|
|
||||||
<el-input class="w-full" size="large" maxlength="30" placeholder="登录账号" v-model="form.username" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-input type="password" size="large" maxlength="30" placeholder="登录密码" v-model="form.password" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-input class="w-full" size="large" maxlength="11" placeholder="请输入手机号码" v-model="form.phone">
|
|
||||||
<template #prepend>+86</template>
|
|
||||||
</el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-space class="flex justify-between w-full">
|
|
||||||
<el-input size="large" placeholder="短信验证码" maxlength="6" class="w-full" v-model="form.code" @keyup.enter.prevent="onSubmitBySms" />
|
|
||||||
<el-button size="large" class="w-full" :disabled="!!countdownTime" @click="checkUser">
|
|
||||||
<span v-if="!countdownTime">发送验证码</span>
|
|
||||||
<span v-else>已发送 {{ countdownTime }} s</span>
|
|
||||||
</el-button>
|
|
||||||
</el-space>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-checkbox v-model="form.isAgree">我已阅读并同意</el-checkbox>
|
|
||||||
<a href="#" class="text-gray-700">《用户协议》</a>
|
|
||||||
<a href="#" class="text-gray-700">《隐私政策》</a>
|
|
||||||
<a href="#" class="text-gray-700">《产品服务协议》</a>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" size="large" class="w-full" :disabled="!form.isAgree" @click="onRegister">注册</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@@ -157,14 +116,15 @@ import {useConfigInfo, useToken, useUser, useWebsite} from "~/composables/config
|
|||||||
import useFormData from '@/utils/use-form-data';
|
import useFormData from '@/utils/use-form-data';
|
||||||
import type { User } from '@/api/system/user/model';
|
import type { User } from '@/api/system/user/model';
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { Shop, Key, Avatar, Briefcase } from '@element-plus/icons-vue'
|
import { Shop, Key, Avatar, Briefcase, FullScreen } from '@element-plus/icons-vue'
|
||||||
import {useServerRequest} from "~/composables/useServerRequest";
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
import type {ApiResult} from "~/api";
|
import type {ApiResult} from "~/api";
|
||||||
import type {CaptchaResult, LoginResult} from "~/api/passport/login/model";
|
import type {CaptchaResult, LoginResult} from "~/api/passport/login/model";
|
||||||
import {getCaptcha, sendSmsCaptcha} from "~/api/passport/login";
|
import {getCaptcha, loginBySms, register, sendSmsCaptcha} from "~/api/passport/login";
|
||||||
|
|
||||||
// 配置信息
|
// 配置信息
|
||||||
const runtimeConfig = useRuntimeConfig();
|
const runtimeConfig = useRuntimeConfig();
|
||||||
|
const route = useRoute();
|
||||||
const website = useWebsite();
|
const website = useWebsite();
|
||||||
const config = useConfigInfo();
|
const config = useConfigInfo();
|
||||||
const token = useToken();
|
const token = useToken();
|
||||||
@@ -295,20 +255,17 @@ const onSubmit = async () => {
|
|||||||
* 短信验证码登录
|
* 短信验证码登录
|
||||||
*/
|
*/
|
||||||
const onSubmitBySms = async () => {
|
const onSubmitBySms = async () => {
|
||||||
const {data: response} = await useServerRequest<ApiResult<LoginResult>>('/loginBySms',{baseURL: runtimeConfig.public.apiServer,method: "post",body: {
|
loginBySms({
|
||||||
phone: form.phone,
|
phone: form.phone,
|
||||||
code: form.code,
|
code: form.code,
|
||||||
isSuperAdmin: true
|
isSuperAdmin: true
|
||||||
}})
|
}).then(response => {
|
||||||
// 登录成功
|
ElMessage.success('登录成功')
|
||||||
if(response.value?.code == 0){
|
doLogin(response)
|
||||||
ElMessage.success(response.value?.message)
|
}).catch(() => {
|
||||||
await doLogin(response.value.data)
|
ElMessage.error('验证码错误')
|
||||||
}
|
changeCaptcha()
|
||||||
if(response.value?.code != 0){
|
})
|
||||||
ElMessage.error(response.value?.message)
|
|
||||||
await changeCaptcha()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -319,7 +276,8 @@ const onRegister = async () => {
|
|||||||
lock: true,
|
lock: true,
|
||||||
text: 'Loading'
|
text: 'Loading'
|
||||||
})
|
})
|
||||||
await useClientRequest<ApiResult<LoginResult>>('/register',{method: "post",body: {
|
|
||||||
|
register({
|
||||||
companyName: '应用名称',
|
companyName: '应用名称',
|
||||||
username: form.phone,
|
username: form.phone,
|
||||||
phone: form.phone,
|
phone: form.phone,
|
||||||
@@ -327,23 +285,38 @@ const onRegister = async () => {
|
|||||||
code: form.code,
|
code: form.code,
|
||||||
email: form.email,
|
email: form.email,
|
||||||
isSuperAdmin: true
|
isSuperAdmin: true
|
||||||
}}).then(response => {
|
}).then(response => {
|
||||||
// 登录成功
|
|
||||||
if(response?.code == 0){
|
|
||||||
loading.close();
|
loading.close();
|
||||||
ElMessage.success(response?.message)
|
ElMessage.success('注册成功')
|
||||||
doLogin(response.data)
|
doLogin(response)
|
||||||
}
|
|
||||||
if(response?.code != 0){
|
|
||||||
loading.close;
|
|
||||||
ElMessage.error(response?.message)
|
|
||||||
changeCaptcha()
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
loading.close();
|
loading.close();
|
||||||
}).finally(() => {
|
|
||||||
loading.close();
|
|
||||||
})
|
})
|
||||||
|
// await useClientRequest<ApiResult<LoginResult>>('/register',{method: "post",body: {
|
||||||
|
// companyName: '应用名称',
|
||||||
|
// username: form.phone,
|
||||||
|
// phone: form.phone,
|
||||||
|
// password: form.password,
|
||||||
|
// code: form.code,
|
||||||
|
// email: form.email,
|
||||||
|
// isSuperAdmin: true
|
||||||
|
// }}).then(response => {
|
||||||
|
// // 登录成功
|
||||||
|
// if(response?.code == 0){
|
||||||
|
// loading.close();
|
||||||
|
// ElMessage.success(response?.message)
|
||||||
|
// doLogin(response.data)
|
||||||
|
// }
|
||||||
|
// if(response?.code != 0){
|
||||||
|
// loading.close;
|
||||||
|
// ElMessage.error(response?.message)
|
||||||
|
// changeCaptcha()
|
||||||
|
// }
|
||||||
|
// }).catch(() => {
|
||||||
|
// loading.close();
|
||||||
|
// }).finally(() => {
|
||||||
|
// loading.close();
|
||||||
|
// })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,14 +339,26 @@ const doLogin = async (data: any) => {
|
|||||||
localStorage.setItem('UserId',data.user.userId);
|
localStorage.setItem('UserId',data.user.userId);
|
||||||
localStorage.setItem('Avatar',data.user.avatar);
|
localStorage.setItem('Avatar',data.user.avatar);
|
||||||
localStorage.setItem('TID_ADMIN',data.user.tenantId);
|
localStorage.setItem('TID_ADMIN',data.user.tenantId);
|
||||||
|
// localStorage.setItem('TenantId',data.user.tenantId);
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigateTo('/')
|
navigateTo('/')
|
||||||
return;
|
|
||||||
},500)
|
},500)
|
||||||
}
|
}
|
||||||
|
|
||||||
changeCaptcha();
|
changeCaptcha();
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.query.type,
|
||||||
|
(type) => {
|
||||||
|
loginBar.value = true
|
||||||
|
activeName.value = 'account'
|
||||||
|
if(type == 'register'){
|
||||||
|
loginBar.value = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.login{
|
.login{
|
||||||
|
|||||||
@@ -1,36 +1,39 @@
|
|||||||
<template>
|
<template>
|
||||||
<PageBanner title="入驻" desc="Register Account"/>
|
<!-- 主体部分 -->
|
||||||
<div class="login-layout m-auto sm:w-screen-xl w-full">
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
<div class="m-auto flex sm:flex-row flex-col sm:px-0 px-3 ">
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
<div class="flash bg-white rounded-lg px-8 py-4 w-full">
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 注册 </span>
|
||||||
|
</template>
|
||||||
|
</el-page-header>
|
||||||
|
<el-card shadow="hover" class=" my-5 px-2">
|
||||||
<Auth @done="reload"/>
|
<Auth @done="reload"/>
|
||||||
</div>
|
</el-card>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import {ArrowLeft, View, Search} from '@element-plus/icons-vue'
|
||||||
import {useConfigInfo, useWebsite} from "~/composables/configState";
|
import {useConfigInfo, useWebsite} from "~/composables/configState";
|
||||||
import {ref} from 'vue'
|
import { ref } from 'vue'
|
||||||
import {useServerRequest} from "~/composables/useServerRequest";
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
import type {ApiResult} from "~/api";
|
import type {ApiResult} from "~/api";
|
||||||
import Auth from './components/Auth.vue';
|
import Auth from './components/Auth.vue';
|
||||||
import type {ShopMerchantApply} from "~/api/shop/shopMerchantApply/model";
|
|
||||||
import Base from "~/pages/user/components/Base.vue";
|
|
||||||
|
|
||||||
// 配置信息
|
// 配置信息
|
||||||
const runtimeConfig = useRuntimeConfig();
|
const runtimeConfig = useRuntimeConfig();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
const activeIndex = ref('');
|
const activeIndex = ref('');
|
||||||
const website = useWebsite()
|
const website = useWebsite()
|
||||||
const config = useConfigInfo();
|
const config = useConfigInfo();
|
||||||
const merchantApply = ref<ShopMerchantApply>();
|
const merchantApply = ref<any>();
|
||||||
|
|
||||||
const reload = async () => {
|
const reload = async () => {
|
||||||
const {data: response} = await useServerRequest<ApiResult<ShopMerchantApply>>('/shop/shop-merchant-apply/getByUserId', {baseURL: runtimeConfig.public.apiServer})
|
const {data: response} = await useServerRequest<ApiResult<any>>('/shop/shop-merchant-apply/getByUserId', {baseURL: runtimeConfig.public.apiServer})
|
||||||
if (response.value?.data) {
|
if (response.value?.data) {
|
||||||
merchantApply.value = response.value.data;
|
merchantApply.value = response.value.data;
|
||||||
}
|
}
|
||||||
if(config.value){
|
if (config.value) {
|
||||||
useHead({
|
useHead({
|
||||||
title: `实名认证 - ${config.value?.siteName}`,
|
title: `实名认证 - ${config.value?.siteName}`,
|
||||||
meta: [{name: website.value.keywords, content: website.value.comments}]
|
meta: [{name: website.value.keywords, content: website.value.comments}]
|
||||||
@@ -38,11 +41,15 @@ const reload = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
(path) => {
|
(path) => {
|
||||||
activeIndex.value = path;
|
activeIndex.value = path;
|
||||||
reload();
|
// reload();
|
||||||
},
|
},
|
||||||
{immediate: true}
|
{immediate: true}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
<template>
|
|
||||||
|
|
||||||
<!-- 主体部分 -->
|
|
||||||
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
|
||||||
<el-row :gutter="24" id="container" class="clearfix">
|
|
||||||
<el-col :span="5" class="left">
|
|
||||||
<!-- 内页左侧组件 -->
|
|
||||||
<Left :category="category" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="19" class="right">
|
|
||||||
<div class="sitemp h-[32px] flex justify-between">
|
|
||||||
<h2>
|
|
||||||
{{ $t('searchKeywords') }}:{{ where.keywords }}
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<el-alert v-if="where.keywords" :title="`${$t('search.results')}:${$t('search.find')} ${total} ${$t('search.nums')}`" type="warning" :closable="false" />
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
<ul class="news_listn clearfix">
|
|
||||||
<template v-for="(item,index) in list" key="index">
|
|
||||||
<li class="clearfix">
|
|
||||||
<a :href="detail(item)" target="_blank" class="n-left fl">
|
|
||||||
<el-image :src="item.image" :fit="`scale-down`" class="w-[240px] h-[158px]" :alt="item.title" />
|
|
||||||
</a>
|
|
||||||
<div class="n-right fr">
|
|
||||||
<h3><a :href="detail(item)" target="_blank" :title="item.title" v-html="replaceKeywords(item.title)"></a></h3>
|
|
||||||
<div v-html="replaceKeywords(item.comments)" class="line-clamp-2"></div>
|
|
||||||
<div class="date">{{ $t('createTime') }}:{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</div>
|
|
||||||
<div class="date">{{ $t('search.column') }}:{{ item.categoryName }}</div>
|
|
||||||
<div class="n-more"><a :href="detail(item)">{{ $t('seeMore') }}>></a></div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
<div class="clearboth"></div>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<Pagination :total="total" @done="search" />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import Banner from "@/components/Banner.vue";
|
|
||||||
import {useLayout, usePage} from "~/composables/configState";
|
|
||||||
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
|
|
||||||
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import {ArrowRight} from '@element-plus/icons-vue'
|
|
||||||
import {detail, getPath} from "~/utils/common";
|
|
||||||
import Left from "~/components/Left.vue";
|
|
||||||
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
|
|
||||||
import {pageCmsArticle} from "~/api/cms/cmsArticle";
|
|
||||||
import {listCmsModel} from "~/api/cms/cmsModel";
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
|
|
||||||
// 页面信息
|
|
||||||
const list = ref<CmsArticle[]>([]);
|
|
||||||
const i18n = useI18n();
|
|
||||||
const category = ref<CmsNavigation[]>([]);
|
|
||||||
const total = ref(0);
|
|
||||||
|
|
||||||
// 获取状态
|
|
||||||
const page = usePage();
|
|
||||||
const layout = useLayout();
|
|
||||||
|
|
||||||
// 搜索表单
|
|
||||||
const where = reactive<CmsArticleParam>({
|
|
||||||
keywords: '',
|
|
||||||
page: 1,
|
|
||||||
limit: 10,
|
|
||||||
status: 0,
|
|
||||||
parentId: undefined,
|
|
||||||
categoryId: undefined,
|
|
||||||
lang: i18n.locale.value
|
|
||||||
});
|
|
||||||
|
|
||||||
const replaceKeywords = (text: any) => {
|
|
||||||
return text.replace(`${where.keywords}`,'<font color=#ff0000>' + where.keywords + '</font>');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载页面数据
|
|
||||||
const reload = async () => {
|
|
||||||
listCmsModel({
|
|
||||||
model: getPath(1)
|
|
||||||
}).then(response => {
|
|
||||||
const data = response[0];
|
|
||||||
if(data){
|
|
||||||
// 获取栏目信息
|
|
||||||
page.value = data
|
|
||||||
layout.value.banner = data.banner;
|
|
||||||
|
|
||||||
// 设置页面标题
|
|
||||||
useSeoMeta({
|
|
||||||
description: data?.comments || `${route.params.id}`,
|
|
||||||
keywords: `${route.params.id}`,
|
|
||||||
titleTemplate: `【搜索结果】${route.params.id}` + ' - %s',
|
|
||||||
})
|
|
||||||
// 二级栏目分类
|
|
||||||
listCmsNavigation({
|
|
||||||
parentId: 2847,
|
|
||||||
}).then(categoryData => {
|
|
||||||
category.value = categoryData;
|
|
||||||
// 加载文章列表
|
|
||||||
if(!getPath(1)){
|
|
||||||
return ElMessage.error('请输入搜索关键词!');
|
|
||||||
}
|
|
||||||
where.keywords = `${route.params.id}`;
|
|
||||||
pageCmsArticle(where).then(response => {
|
|
||||||
if(response){
|
|
||||||
total.value = response?.count;
|
|
||||||
list.value = response?.list;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err,'加载失败...')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 搜索
|
|
||||||
* @param data
|
|
||||||
*/
|
|
||||||
const search = (data: CmsArticleParam) => {
|
|
||||||
where.page = data.page;
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => route.path,
|
|
||||||
() => {
|
|
||||||
reload();
|
|
||||||
},
|
|
||||||
{immediate: true}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
<style scoped lang="less">
|
|
||||||
.sitemp h2{
|
|
||||||
width: 500px !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
123
pages/search/[keywords].vue
Normal file
123
pages/search/[keywords].vue
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 主体部分 -->
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 mt-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> {{ '站内搜索' }} </span>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<el-radio-group v-model="where.model" @change="reload">
|
||||||
|
<el-radio-button label="文档" value="docs" />
|
||||||
|
<el-radio-button label="资讯" value="article" />
|
||||||
|
</el-radio-group>
|
||||||
|
</template>
|
||||||
|
<el-row :gutter="24" id="container" class="clearfix">
|
||||||
|
<el-col v-for="(item,index) in list" :key="index" :span="6" class="left mb-6">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer">
|
||||||
|
<nuxt-link :to="`/${item.detail}/${item.articleId}.html`">
|
||||||
|
<el-image
|
||||||
|
:src="item.image"
|
||||||
|
fit="cover"
|
||||||
|
:lazy="true" class="w-full md:h-[166px] h-[199px] cursor-pointer bg-gray-50"/>
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-6 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col gap-1.5">
|
||||||
|
<div class="flex-1 text-xl cursor-pointer flex min-h-[56px]">
|
||||||
|
<span v-html="replaceKeywords(item.title)"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
||||||
|
<el-space class="flex items-end">
|
||||||
|
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
||||||
|
</el-space>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
{{ dayjs(item.createTime).format('YYYY-MM-DD') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nuxt-link>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<Pagination :total="total" @done="search" :keywords="where.keywords" />
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Banner from "@/components/Banner.vue";
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useLayout, usePage} from "~/composables/configState";
|
||||||
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import {getViews} from "~/utils/common";
|
||||||
|
import {pageCmsArticle} from "~/api/cms/cmsArticle";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
// 页面信息
|
||||||
|
const list = ref<CmsArticle[]>([]);
|
||||||
|
const i18n = useI18n();
|
||||||
|
const total = ref(0);
|
||||||
|
|
||||||
|
// 获取状态
|
||||||
|
const page = usePage();
|
||||||
|
const layout = useLayout();
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const where = reactive<CmsArticleParam>({
|
||||||
|
keywords: undefined,
|
||||||
|
page: 1,
|
||||||
|
limit: 12,
|
||||||
|
status: 0,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
lang: i18n.locale.value
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载页面数据
|
||||||
|
const reload = async () => {
|
||||||
|
list.value = [];
|
||||||
|
|
||||||
|
pageCmsArticle(where).then(response => {
|
||||||
|
list.value = response?.list || [];
|
||||||
|
total.value = response?.count || 0;
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置页面标题
|
||||||
|
useSeoMeta({
|
||||||
|
description: `${where.keywords || route.params.keywords}`,
|
||||||
|
keywords: `${where.keywords || route.params.keywords}`,
|
||||||
|
titleTemplate: `【搜索结果】${where.keywords || route.params.keywords}` + ' - %s',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
const search = (data: CmsArticleParam) => {
|
||||||
|
where.page = data.page;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
|
const replaceKeywords = (text: any) => {
|
||||||
|
return text.replace(`${where.keywords}`,'<font color=#ff0000>' + where.keywords + '</font>');
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.params.keywords,
|
||||||
|
(keywords) => {
|
||||||
|
where.keywords = String(keywords);
|
||||||
|
if(where.keywords == '关键词不能为空!'){
|
||||||
|
where.keywords = undefined;
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
53
pages/search/components/ArticleList.vue
Normal file
53
pages/search/components/ArticleList.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<el-col v-for="(item,index) in data" :key="index" :span="6" class="left mb-6">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer">
|
||||||
|
<nuxt-link :to="`/${item.detail}/${item.articleId}.html`">
|
||||||
|
<el-image
|
||||||
|
:src="item.image"
|
||||||
|
fit="cover"
|
||||||
|
:lazy="true" class="w-full md:h-[166px] h-[199px] cursor-pointer bg-gray-50"/>
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-6 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col gap-1.5">
|
||||||
|
<div class="flex-1 text-xl cursor-pointer flex min-h-[56px]">
|
||||||
|
<span v-html="replaceKeywords(item.title)"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
||||||
|
<el-space class="flex items-end">
|
||||||
|
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
||||||
|
</el-space>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
{{ dayjs(item.createTime).format('YYYY-MM-DD') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nuxt-link>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { View } from '@element-plus/icons-vue'
|
||||||
|
import {getViews} from "~/utils/common";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
data?: CmsArticle[];
|
||||||
|
keywords?: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: CmsArticleParam): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const replaceKeywords = (text: any) => {
|
||||||
|
return text.replace(`${props.keywords}`,'<font color=#ff0000>' + props.keywords + '</font>');
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
53
pages/search/components/SiteList.vue
Normal file
53
pages/search/components/SiteList.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<el-col v-for="(item,index) in data" :key="index" :span="6" class="left mb-6">
|
||||||
|
<el-card shadow="hover" :body-style="{ padding: '0px' }" class=" hover:bg-gray-50 cursor-pointer">
|
||||||
|
<nuxt-link :to="`/item/${item.websiteId}.html`">
|
||||||
|
<el-image
|
||||||
|
:src="item.websiteLogo"
|
||||||
|
fit="cover"
|
||||||
|
:lazy="true" class="w-full md:h-[166px] h-[199px] cursor-pointer bg-gray-50"/>
|
||||||
|
<div class="flex-1 px-4 py-5 sm:p-6 !p-4">
|
||||||
|
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col gap-1.5">
|
||||||
|
<div class="flex-1 text-xl cursor-pointer flex min-h-[56px]">
|
||||||
|
<span v-html="replaceKeywords(item.websiteName)"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button-group flex justify-between items-center mt-3 text-sm">
|
||||||
|
<el-space class="flex items-end">
|
||||||
|
<div class="text-gray-400 gap-1 flex items-center"><el-icon><View /></el-icon><span>{{ getViews(item) }}</span></div>
|
||||||
|
</el-space>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
{{ dayjs(item.createTime).format('YYYY-MM-DD') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nuxt-link>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { View } from '@element-plus/icons-vue'
|
||||||
|
import {getViews} from "~/utils/common";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import type {CmsWebsite, CmsWebsiteParam} from "~/api/cms/cmsWebsite/model";
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
data?: CmsWebsite[];
|
||||||
|
keywords?: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', where: CmsWebsiteParam): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const replaceKeywords = (text: any) => {
|
||||||
|
return text.replace(`${props.keywords}`,'<font color=#ff0000>' + props.keywords + '</font>');
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
</style>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<div class="flex flex-1">
|
<div class="flex flex-1">
|
||||||
<template v-if="form.image">
|
<template v-if="form.image">
|
||||||
<el-image :src="form.image" shape="square"
|
<el-image :src="form.image" shape="square"
|
||||||
class="hidden-sm-and-down bg-white w-[128px] h-[128px] cursor-pointer rounded-avatar shadow-sm hover:shadow mr-4"/>
|
class="hidden-sm-and-down bg-white w-[128px] h-[128px] cursor-pointer rounded-avatar shadow-sm hover:shadow mr-6"/>
|
||||||
<!-- <el-image :src="form.image" shape="square" :size="80"-->
|
<!-- <el-image :src="form.image" shape="square" :size="80"-->
|
||||||
<!-- class="hidden-sm-and-up bg-white rounded-avatar-xs shadow-sm hover:shadow mr-4"/>-->
|
<!-- class="hidden-sm-and-up bg-white rounded-avatar-xs shadow-sm hover:shadow mr-4"/>-->
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
72
pages/user/auth.vue
Normal file
72
pages/user/auth.vue
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 my-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 实名认证 </span>
|
||||||
|
</template>
|
||||||
|
<div class="login-layout m-auto mt-10 sm:w-screen-xl w-full">
|
||||||
|
<div class="m-auto flex sm:flex-row flex-col sm:px-0 px-3 ">
|
||||||
|
<!-- 用户菜单 -->
|
||||||
|
<UserMenu :activeIndex="activeIndex" @done="reload"/>
|
||||||
|
<div class="flash bg-white rounded-lg w-full">
|
||||||
|
<div class="sm:w-screen-md w-full sm:px-4 sm:py-2">
|
||||||
|
<Auth @done="reload"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useConfigInfo, useWebsite} from "~/composables/configState";
|
||||||
|
import {ref} from 'vue'
|
||||||
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
|
import type {ApiResult} from "~/api";
|
||||||
|
import UserMenu from "./components/UserMenu.vue";
|
||||||
|
import Auth from './components/Auth.vue';
|
||||||
|
import type {ShopMerchantApply} from "~/api/shop/shopMerchantApply/model";
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const runtimeConfig = useRuntimeConfig();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const activeIndex = ref('');
|
||||||
|
const website = useWebsite()
|
||||||
|
const config = useConfigInfo();
|
||||||
|
const merchantApply = ref<ShopMerchantApply>();
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
// 未登录状态(是否强制登录)
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token || token == '') {
|
||||||
|
navigateTo('/passport/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const {data: response} = await useServerRequest<ApiResult<ShopMerchantApply>>('/shop/shop-merchant-apply/getByUserId', {baseURL: runtimeConfig.public.apiServer})
|
||||||
|
if (response.value?.data) {
|
||||||
|
merchantApply.value = response.value.data;
|
||||||
|
}
|
||||||
|
if(config.value){
|
||||||
|
useHead({
|
||||||
|
title: `实名认证 - ${config.value?.siteName}`,
|
||||||
|
meta: [{name: website.value.keywords, content: website.value.comments}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
(path) => {
|
||||||
|
activeIndex.value = path;
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{immediate: true}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
460
pages/user/components/Auth.vue
Normal file
460
pages/user/components/Auth.vue
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
v-loading="loading"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-position="top"
|
||||||
|
class="w-full sm:py-2 ml-4 mt-1"
|
||||||
|
size="large"
|
||||||
|
status-icon
|
||||||
|
>
|
||||||
|
<el-tabs v-model="form.type" class="flash bg-white ml-0">
|
||||||
|
<el-tab-pane :name="0" label="个人认证"/>
|
||||||
|
<el-tab-pane :name="1" label="企业认证"/>
|
||||||
|
</el-tabs>
|
||||||
|
<!-- 已完成认证 -->
|
||||||
|
<template v-if="form.status === 1">
|
||||||
|
<template v-if="form.type == 0">
|
||||||
|
<el-result
|
||||||
|
icon="success"
|
||||||
|
title="个人认证已通过"
|
||||||
|
:sub-title="`认证完成时间 ${form.completedTime}`"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<el-button type="text" @click="onUpdate">修改认证信息</el-button>
|
||||||
|
</template>
|
||||||
|
</el-result>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-result
|
||||||
|
icon="success"
|
||||||
|
title="企业认证已通过"
|
||||||
|
:sub-title="`认证完成时间 ${form.completedTime}`"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<el-button type="text" @click="onUpdate">修改认证信息</el-button>
|
||||||
|
</template>
|
||||||
|
</el-result>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<!-- 申请被驳回 -->
|
||||||
|
<template v-if="form.status === 2">
|
||||||
|
<el-result
|
||||||
|
icon="error"
|
||||||
|
title="您的申请已被驳回"
|
||||||
|
:sub-title="`${form.reason}`"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<el-button type="text" @click="onUpdate">修改认证信息</el-button>
|
||||||
|
</template>
|
||||||
|
</el-result>
|
||||||
|
</template>
|
||||||
|
<!-- 未完成认证 -->
|
||||||
|
<template v-if="form.status === 0 && form.checkStatus">
|
||||||
|
<el-result
|
||||||
|
icon="warning"
|
||||||
|
title="审核中"
|
||||||
|
:sub-title="`您的申请已提交,请耐心等待工作人员的审核,非常感谢`"
|
||||||
|
>
|
||||||
|
</el-result>
|
||||||
|
</template>
|
||||||
|
<template v-if="form.status === 0 && !form.checkStatus">
|
||||||
|
<template v-if="form.type == 1">
|
||||||
|
<el-form-item label="企业名称" prop="merchantName">
|
||||||
|
<el-input v-model="form.merchantName" placeholder="请输入企业名称"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="社会信用代码" prop="merchantCode">
|
||||||
|
<el-input v-model="form.merchantCode" placeholder="请输入社会信用代码"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="营业执照" required>
|
||||||
|
<el-upload
|
||||||
|
v-model:file-list="yyzzFile"
|
||||||
|
action="https://common-api.websoft.top/api/oss/upload"
|
||||||
|
:headers="{
|
||||||
|
Authorization: token,
|
||||||
|
TenantId: tenantId,
|
||||||
|
}"
|
||||||
|
:limit="1"
|
||||||
|
list-type="picture-card"
|
||||||
|
:on-preview="handlePictureCardPreview"
|
||||||
|
:on-remove="yyzzRemove"
|
||||||
|
:on-success="yyzzOnSuccess"
|
||||||
|
>
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</el-upload>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img w-full :src="dialogImageUrl" alt="Preview Image" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="门头照片">
|
||||||
|
<el-upload
|
||||||
|
v-model:file-list="image"
|
||||||
|
action="https://common-api.websoft.top/api/oss/upload"
|
||||||
|
:headers="{
|
||||||
|
Authorization: token,
|
||||||
|
TenantId: tenantId,
|
||||||
|
}"
|
||||||
|
:limit="1"
|
||||||
|
list-type="picture-card"
|
||||||
|
:on-preview="handlePictureCardPreview"
|
||||||
|
:on-remove="imageRemove"
|
||||||
|
:on-success="imageOnSuccess"
|
||||||
|
>
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</el-upload>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img w-full :src="dialogImageUrl" alt="Preview Image" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="其他证件">
|
||||||
|
<el-upload
|
||||||
|
v-model:file-list="files"
|
||||||
|
action="https://common-api.websoft.top/api/oss/upload"
|
||||||
|
:headers="{
|
||||||
|
Authorization: token,
|
||||||
|
TenantId: tenantId,
|
||||||
|
}"
|
||||||
|
:limit="9"
|
||||||
|
list-type="picture-card"
|
||||||
|
:on-preview="handlePictureCardPreview"
|
||||||
|
:on-remove="filesRemove"
|
||||||
|
:on-success="filesOnSuccess"
|
||||||
|
>
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</el-upload>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<img w-full :src="dialogImageUrl" alt="Preview Image" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
<el-form-item label="真实姓名" prop="realName">
|
||||||
|
<el-input v-model="form.realName" placeholder="请输入真实姓名"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号码" prop="phone">
|
||||||
|
<el-input v-model="form.phone" maxlength="11" placeholder="请输入真实有效的手机号码"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证号码" prop="idCard">
|
||||||
|
<el-input v-model="form.idCard" placeholder="请输入证件号码"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份证" required>
|
||||||
|
<el-upload
|
||||||
|
v-model:file-list="sfzFile"
|
||||||
|
action="https://common-api.websoft.top/api/oss/upload"
|
||||||
|
:headers="{
|
||||||
|
Authorization: token,
|
||||||
|
TenantId: tenantId,
|
||||||
|
}"
|
||||||
|
:limit="2"
|
||||||
|
list-type="picture-card"
|
||||||
|
:on-preview="handlePictureCardPreview"
|
||||||
|
:on-remove="sfzRemove"
|
||||||
|
:on-success="sfzSuccess"
|
||||||
|
>
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
</el-upload>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属行业" prop="category">
|
||||||
|
<el-cascader
|
||||||
|
v-model="industry"
|
||||||
|
:options="industryData"
|
||||||
|
placeholder="请选择所属行业"
|
||||||
|
class="w-full"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="业务描述" prop="comments">
|
||||||
|
<el-input v-model="form.comments" placeholder="请输入公司业务介绍" :rows="5" type="textarea" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="注册协议">
|
||||||
|
<el-checkbox v-model="isAgree">
|
||||||
|
请务必提供真实信息,我司有权自行或委托第三方审查您提供的身份信息是否属真实,有效。若提供虚假信息,由此的全部后果由您承担。
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-space class="flex">
|
||||||
|
<el-button type="primary" size="large" :disabled="!isAgree" @click="submitForm(formRef)">
|
||||||
|
{{ isUpdate ? '提交修改' : '提交申请' }}
|
||||||
|
</el-button>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
<el-dialog v-model="dialogVisible">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<el-image w-full :src="dialogImageUrl" alt="查看证件" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {reactive, ref} from 'vue'
|
||||||
|
import {Plus} from '@element-plus/icons-vue'
|
||||||
|
import type {FormInstance, FormRules, UploadProps, UploadUserFile} from 'element-plus'
|
||||||
|
import type {ShopMerchantApply} from "~/api/shop/shopMerchantApply/model";
|
||||||
|
import industryData from '@/assets/json/industry-data.json';
|
||||||
|
import {useClientRequest} from "~/composables/useClientRequest";
|
||||||
|
import type {ApiResult} from "~/api";
|
||||||
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
|
import type {ShopMerchant} from "~/api/shop/shopMerchant/model";
|
||||||
|
import useFormData from "~/utils/use-form-data";
|
||||||
|
|
||||||
|
const token = useToken();
|
||||||
|
const tenantId = localStorage.getItem('TID_ADMIN')
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const yyzzFile = ref<UploadUserFile[]>([])
|
||||||
|
const sfzFile = ref<UploadUserFile[]>([])
|
||||||
|
const sfzStr = ref<string[]>([]);
|
||||||
|
const files = ref<UploadUserFile[]>([])
|
||||||
|
const filesStr = ref<string[]>([])
|
||||||
|
const image = ref<UploadUserFile[]>([])
|
||||||
|
const industry = ref<any[]>([])
|
||||||
|
const loading = ref<boolean>(true)
|
||||||
|
const isUpdate = ref<boolean>(false)
|
||||||
|
const isAgree = ref<boolean>(false)
|
||||||
|
|
||||||
|
const dialogImageUrl = ref('')
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
|
||||||
|
const {form, assignFields, resetFields} = useFormData<ShopMerchantApply>({
|
||||||
|
applyId: undefined,
|
||||||
|
type: 0,
|
||||||
|
merchantName: undefined,
|
||||||
|
merchantCode: undefined,
|
||||||
|
image: undefined,
|
||||||
|
phone: undefined,
|
||||||
|
realName: undefined,
|
||||||
|
idCard: undefined,
|
||||||
|
sfz1: undefined,
|
||||||
|
sfz2: undefined,
|
||||||
|
yyzz: undefined,
|
||||||
|
name2: undefined,
|
||||||
|
shopType: undefined,
|
||||||
|
parentId: undefined,
|
||||||
|
categoryId: undefined,
|
||||||
|
category: undefined,
|
||||||
|
commission: undefined,
|
||||||
|
keywords: undefined,
|
||||||
|
files: undefined,
|
||||||
|
ownStore: undefined,
|
||||||
|
recommend: undefined,
|
||||||
|
completedTime: undefined,
|
||||||
|
goodsReview: undefined,
|
||||||
|
userId: undefined,
|
||||||
|
comments: undefined,
|
||||||
|
reason: undefined,
|
||||||
|
checkStatus: undefined,
|
||||||
|
status: 0,
|
||||||
|
sortNumber: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = reactive<FormRules<ShopMerchantApply>>({
|
||||||
|
realName: [
|
||||||
|
{required: true, message: '请输入真实姓名', trigger: 'blur'},
|
||||||
|
{min: 2, max: 5, message: '长度应为2-5个字符', trigger: 'blur'},
|
||||||
|
],
|
||||||
|
phone: [
|
||||||
|
{required: true, message: '请输入手机号码', trigger: 'blur'},
|
||||||
|
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur'},
|
||||||
|
],
|
||||||
|
idCard: [
|
||||||
|
{required: true, message: '请输入证件号码', trigger: 'blur'},
|
||||||
|
{min: 18, max: 18, message: '证件号码长度应为18位', trigger: 'blur'},
|
||||||
|
],
|
||||||
|
merchantName: [
|
||||||
|
{required: true, message: '请输入企业名称', trigger: 'blur'}
|
||||||
|
],
|
||||||
|
merchantCode: [
|
||||||
|
{required: true, message: '请输入社会信用代码', trigger: 'blur'}
|
||||||
|
],
|
||||||
|
category: [
|
||||||
|
{required: true, message: '请选择所属行业', trigger: 'change'}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const yyzzRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
||||||
|
form.yyzz = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const yyzzOnSuccess = (e: any) => {
|
||||||
|
form.yyzz = e.data.downloadUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
const sfzRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
||||||
|
form.sfz1 = '';
|
||||||
|
form.sfz2 = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const sfzSuccess = (e:any) => {
|
||||||
|
sfzStr.value.push(e.data.downloadUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageOnSuccess = (e: any) => {
|
||||||
|
form.image = e.data.downloadUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
|
||||||
|
form.image = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const filesRemove: UploadProps['onRemove'] = (uploadFile) => {
|
||||||
|
const index = filesStr.value.findIndex(f => f == uploadFile.url);
|
||||||
|
filesStr.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const filesOnSuccess = (e: any) => {
|
||||||
|
filesStr.value.push(e.data.downloadUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所属行业
|
||||||
|
const handleChange = (value: any) => {
|
||||||
|
let parent = ''
|
||||||
|
let category = ''
|
||||||
|
industryData.map(d => {
|
||||||
|
if (d.value == value[0]) {
|
||||||
|
form.parentId = d.value
|
||||||
|
parent = d.label
|
||||||
|
if (d.children) {
|
||||||
|
d.children.map(c => {
|
||||||
|
if (c.value == value[1]) {
|
||||||
|
category = c.label
|
||||||
|
form.categoryId = c.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
form.category = `${parent}/${category}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const onUpdate = () => {
|
||||||
|
form.status = 0;
|
||||||
|
form.checkStatus = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
|
||||||
|
dialogImageUrl.value = uploadFile.url!
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const runtimeConfig = useRuntimeConfig();
|
||||||
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
console.log('submit!',valid)
|
||||||
|
if (form.type == 0) {
|
||||||
|
form.shopType = '个人开发者';
|
||||||
|
form.merchantName = form.realName;
|
||||||
|
}
|
||||||
|
if(form.type == 1){
|
||||||
|
form.shopType = '企业开发者';
|
||||||
|
if(form.yyzz == ''){
|
||||||
|
return ElMessage.error('请上营业执照');
|
||||||
|
}
|
||||||
|
if(filesStr.value.length > 0){
|
||||||
|
form.files = JSON.stringify(filesStr.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(sfzStr.value.length == 1){
|
||||||
|
return ElMessage.error('请上传身份证正反面');
|
||||||
|
}
|
||||||
|
form.sfz1 = sfzStr.value[0];
|
||||||
|
form.sfz2 = sfzStr.value[1];
|
||||||
|
useClientRequest<ApiResult<any>>(`/shop/shop-merchant-apply`, {
|
||||||
|
baseURL: runtimeConfig.public.apiServer,
|
||||||
|
method: isUpdate.value ? 'PUT' : 'POST',
|
||||||
|
body: form
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
ElMessage.success(res.message)
|
||||||
|
reload();
|
||||||
|
} else {
|
||||||
|
return ElMessage.error(res.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
const {data: response} = await useServerRequest<ApiResult<ShopMerchant>>('/shop/shop-merchant-apply/getByUserId')
|
||||||
|
if (response.value?.data) {
|
||||||
|
isUpdate.value = true;
|
||||||
|
assignFields(response.value.data)
|
||||||
|
industry.value = []
|
||||||
|
industry.value.push(form.parentId)
|
||||||
|
industry.value.push(form.categoryId)
|
||||||
|
files.value = []
|
||||||
|
filesStr.value = []
|
||||||
|
yyzzFile.value = []
|
||||||
|
sfzFile.value = []
|
||||||
|
sfzStr.value = []
|
||||||
|
image.value = []
|
||||||
|
if(form.sfz1){
|
||||||
|
sfzFile.value.push({
|
||||||
|
uid: 1,
|
||||||
|
url: form.sfz1,
|
||||||
|
name: '身份证正面',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(form.sfz2){
|
||||||
|
sfzFile.value.push({
|
||||||
|
uid: 2,
|
||||||
|
url: form.sfz2,
|
||||||
|
name: '身份证反面',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(form.yyzz){
|
||||||
|
yyzzFile.value.push({
|
||||||
|
uid: 3,
|
||||||
|
url: form.yyzz,
|
||||||
|
name: '营业执照',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(form.image){
|
||||||
|
image.value.push({
|
||||||
|
uid: 4,
|
||||||
|
url: form.image,
|
||||||
|
name: '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (form.files) {
|
||||||
|
const arr = JSON.parse(form.files)
|
||||||
|
let i = 1;
|
||||||
|
arr.map(d => {
|
||||||
|
files.value.push({
|
||||||
|
uid: i++,
|
||||||
|
url: d,
|
||||||
|
name: '',
|
||||||
|
})
|
||||||
|
filesStr.value.push(d)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
/* 自定义 el-dialog 的样式 */
|
||||||
|
.el-dialog {
|
||||||
|
background: rgba(255, 255, 255, 0.5); /* 设置背景颜色为半透明白色 */
|
||||||
|
backdrop-filter: blur(10px); /* 可选:为背景添加模糊效果 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
46
pages/user/components/Base.vue
Normal file
46
pages/user/components/Base.vue
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<el-form :model="form" label-width="auto" size="large" label-position="top">
|
||||||
|
<el-form-item label="租户ID" class="px-4">
|
||||||
|
<el-input disabled v-model="form.tenantId"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号码" class="px-4">
|
||||||
|
<el-input disabled v-model="form.mobile"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="应用名称" class="px-4">
|
||||||
|
<el-input v-model="form.tenantName"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="昵称" class="px-4">
|
||||||
|
<el-input v-model="form.nickname"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="邮箱账号" class="px-4">
|
||||||
|
<el-input v-model="form.email" placeholder="邮箱账号"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="性别" class="px-4">
|
||||||
|
<el-radio-group v-model="form.sex">
|
||||||
|
<el-radio value="1">男</el-radio>
|
||||||
|
<el-radio value="2">女</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="个人签名" class="px-4">
|
||||||
|
<el-input v-model="form.comments" type="textarea" placeholder="个人签名" :rows="4"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="px-4">
|
||||||
|
<el-button type="primary" class="sm:w-auto w-full" size="large" @click="onSubmit">保存</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
form?: any;
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
</style>
|
||||||
45
pages/user/components/Order.vue
Normal file
45
pages/user/components/Order.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<el-table :data="tableData">
|
||||||
|
<el-table-column prop="orderId" label="订单号" />
|
||||||
|
<el-table-column prop="comments" label="产品名称" />
|
||||||
|
<el-table-column prop="payPrice" label="订单金额(元)" />
|
||||||
|
<el-table-column prop="month" label="购买时长(月)" />
|
||||||
|
<el-table-column prop="appName" label="应用名称" />
|
||||||
|
<el-table-column prop="createTime" label="下单时间" />
|
||||||
|
<el-table-column prop="action" label="操作">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button @click="openSpmUrl(`https://${scope.row.tenantId}.websoft.top`,form,scope.row.tenantId,true)">控制台</el-button></template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ref} from "vue";
|
||||||
|
import type {ApiResult, PageResult} from "~/api";
|
||||||
|
import type {OrderGoods} from "~/api/system/orderGoods/model";
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
form?: any;
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const tableData = ref<OrderGoods[]>([]);
|
||||||
|
|
||||||
|
const {data: response} = await useServerRequest<ApiResult<PageResult<OrderGoods>>>('/system/order-goods/page',{
|
||||||
|
params: {
|
||||||
|
userId: localStorage.getItem('UserId')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(response.value?.data){
|
||||||
|
tableData.value = response.value.data.list;
|
||||||
|
console.log(tableData.value,'tableData')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
</style>
|
||||||
31
pages/user/components/Password.vue
Normal file
31
pages/user/components/Password.vue
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<el-form :model="form" label-width="auto" size="large" label-position="top">
|
||||||
|
<el-form-item label="旧密码" class="px-4">
|
||||||
|
<el-input v-model="form.oldPassword" placeholder="请输入旧密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="新密码" class="px-4">
|
||||||
|
<el-input v-model="form.password" type="password" placeholder="请输入新密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="确认密码" class="px-4">
|
||||||
|
<el-input v-model="form.password2" type="password" placeholder="请确认新密码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="px-4">
|
||||||
|
<el-button type="primary" size="large" @click="onSubmit">保存</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
form?: any;
|
||||||
|
title?: string;
|
||||||
|
desc?: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
</style>
|
||||||
60
pages/user/components/UserMenu.vue
Normal file
60
pages/user/components/UserMenu.vue
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<el-space direction="vertical" class="sm:w-[140px] sm:flex sm:mb-0 mb-5 w-full pr-7">
|
||||||
|
<div class="py-2" v-for="(item,index) in activities" :index="`${item.path}`" :key="index">
|
||||||
|
<el-button :icon="item.icon" link class="text-gray-500" plain @click="navigateTo(item.path)">{{ item.name }}</el-button>
|
||||||
|
</div>
|
||||||
|
</el-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {User,Lock,Postcard,Tickets,SwitchButton} from '@element-plus/icons-vue'
|
||||||
|
import {navigateTo} from "#imports";
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
layout?: any;
|
||||||
|
activeIndex?: string;
|
||||||
|
}>(),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'done', index: string): void;
|
||||||
|
(e: 'update:visible', visible: boolean): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const activities = [
|
||||||
|
{
|
||||||
|
icon: User,
|
||||||
|
name: '账号信息',
|
||||||
|
path: '/user'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Lock,
|
||||||
|
name: '密码修改',
|
||||||
|
path: '/user/password'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: Postcard,
|
||||||
|
name: '实名认证',
|
||||||
|
path: '/user/auth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: SwitchButton,
|
||||||
|
name: '退出登录',
|
||||||
|
path: '/user/logout'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
const handleSelect = (index: string) => {
|
||||||
|
emit('done', index)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.custom-menu-item:hover {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
108
pages/user/index.vue
Normal file
108
pages/user/index.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 my-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 用户中心 </span>
|
||||||
|
</template>
|
||||||
|
<div class="login-layout mt-10 sm:w-screen-xl w-full">
|
||||||
|
<div class="m-auto flex sm:flex-row flex-col sm:px-0 px-3">
|
||||||
|
<!-- 用户菜单 -->
|
||||||
|
<UserMenu :activeIndex="activeIndex" @done="onDone" class="sm:flex hidden"/>
|
||||||
|
<div class="flash bg-white rounded-lg w-full">
|
||||||
|
<div class="title text-xl text-gray-700 md:px-8 p-4 md:mt-3 font-500">账号信息</div>
|
||||||
|
<div class="sm:w-screen-md w-full sm:px-4 sm:py-2">
|
||||||
|
<Base :form="form"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useWebsite} from "~/composables/configState";
|
||||||
|
import useFormData from '@/utils/use-form-data';
|
||||||
|
import type {User} from '@/api/system/user/model';
|
||||||
|
import {ref} from 'vue'
|
||||||
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
|
import type {ApiResult} from "~/api";
|
||||||
|
import UserMenu from "./components/UserMenu.vue";
|
||||||
|
import Base from './components/Base.vue';
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const runtimeConfig = useRuntimeConfig();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const website = useWebsite()
|
||||||
|
const userInfo = ref<User>();
|
||||||
|
const activeIndex = ref('');
|
||||||
|
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const {form, assignFields} = useFormData<User>({
|
||||||
|
userId: undefined,
|
||||||
|
nickname: '',
|
||||||
|
username: '',
|
||||||
|
phone: '',
|
||||||
|
mobile: '',
|
||||||
|
sex: '',
|
||||||
|
sexName: '',
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
code: '',
|
||||||
|
smsCode: '',
|
||||||
|
comments: '',
|
||||||
|
remember: true,
|
||||||
|
tenantId: undefined,
|
||||||
|
tenantName: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: `用户中心`,
|
||||||
|
meta: [{name: website.value.keywords, content: website.value.comments}]
|
||||||
|
});
|
||||||
|
|
||||||
|
const onDone = (index: string) => {
|
||||||
|
activeIndex.value = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
const {data: modify} = await useServerRequest<ApiResult<User>>('/auth/user', {
|
||||||
|
baseURL: runtimeConfig.public.apiServer,
|
||||||
|
method: 'put',
|
||||||
|
body: form
|
||||||
|
})
|
||||||
|
if (modify.value?.code == 0) {
|
||||||
|
ElMessage.success('修改成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
// 未登录状态(是否强制登录)
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token || token == '') {
|
||||||
|
navigateTo('/passport/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const {data: response} = await useServerRequest<ApiResult<User>>('/auth/user', {baseURL: runtimeConfig.public.apiServer})
|
||||||
|
if (response.value?.data) {
|
||||||
|
userInfo.value = response.value?.data;
|
||||||
|
assignFields(response.value?.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
(path) => {
|
||||||
|
activeIndex.value = path;
|
||||||
|
console.log(path, '=>Path')
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{immediate: true}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
34
pages/user/logout.vue
Normal file
34
pages/user/logout.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 my-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 退出登录 </span>
|
||||||
|
</template>
|
||||||
|
<div class="login-layout mt-10 sm:w-screen-xl w-full">
|
||||||
|
<div class="m-auto flex sm:flex-row flex-col sm:px-0 px-3">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useToken} from "~/composables/configState";
|
||||||
|
import UserMenu from "~/pages/user/components/UserMenu.vue";
|
||||||
|
import Base from "~/pages/user/components/Base.vue";
|
||||||
|
|
||||||
|
const token = useToken();
|
||||||
|
const router = useRouter();
|
||||||
|
token.value = '';
|
||||||
|
localStorage.clear();
|
||||||
|
setTimeout(() => {
|
||||||
|
navigateTo('/')
|
||||||
|
return;
|
||||||
|
}, 1000)
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
102
pages/user/order.vue
Normal file
102
pages/user/order.vue
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 my-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 订单列表 </span>
|
||||||
|
</template>
|
||||||
|
<div class="login-layout m-auto mt-10 sm:w-screen-xl w-full">
|
||||||
|
<div class="m-auto flex sm:flex-row flex-col sm:px-0 px-3">
|
||||||
|
<div class=" bg-white rounded-lg w-full">
|
||||||
|
<div class="flash bg-white rounded-lg px-8 py-4 w-auto">
|
||||||
|
<Order :form="form" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useConfigInfo, useToken, useWebsite} from "~/composables/configState";
|
||||||
|
import useFormData from '@/utils/use-form-data';
|
||||||
|
import type { User } from '@/api/system/user/model';
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
|
import type {ApiResult} from "~/api";
|
||||||
|
import UserMenu from "./components/UserMenu.vue";
|
||||||
|
import Order from './components/Order.vue';
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const runtimeConfig = useRuntimeConfig();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const website = useWebsite()
|
||||||
|
const config = useConfigInfo();
|
||||||
|
const token = useToken();
|
||||||
|
const userInfo = ref<User>();
|
||||||
|
const activeIndex = ref('');
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const { form, assignFields } = useFormData<User>({
|
||||||
|
userId: undefined,
|
||||||
|
nickname: '',
|
||||||
|
username: '',
|
||||||
|
phone: '',
|
||||||
|
mobile: '',
|
||||||
|
sex: '',
|
||||||
|
sexName: '',
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
code: '',
|
||||||
|
smsCode: '',
|
||||||
|
comments: '',
|
||||||
|
remember: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableData = ref<any[]>();
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: `用户中心 - ${config.value?.siteName}`,
|
||||||
|
meta: [{ name: website.value.keywords, content: website.value.comments }]
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
const {data: modify } = await useServerRequest<ApiResult<User>>('/auth/user',{
|
||||||
|
baseURL: runtimeConfig.public.apiServer,
|
||||||
|
method: 'put',
|
||||||
|
body: form
|
||||||
|
})
|
||||||
|
if(modify.value?.code == 0){
|
||||||
|
ElMessage.success('修改成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
// 未登录状态(是否强制登录)
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token || token == '') {
|
||||||
|
navigateTo('/passport/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// const {data: response} = await useServerRequest<ApiResult<Order>>('/system/order',{baseURL: runtimeConfig.public.apiServer})
|
||||||
|
// if(response.value?.data){
|
||||||
|
// console.log(response.value,'order')
|
||||||
|
// // userInfo.value = response.value?.data;
|
||||||
|
// // assignFields(response.value?.data);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
(path) => {
|
||||||
|
activeIndex.value = path;
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
151
pages/user/password.vue
Normal file
151
pages/user/password.vue
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<template>
|
||||||
|
<div class="xl:w-screen-xl m-auto py-4 my-20">
|
||||||
|
<el-page-header :icon="ArrowLeft" @back="goBack">
|
||||||
|
<template #content>
|
||||||
|
<span class="text-large font-600 mr-3"> 用户中心 </span>
|
||||||
|
</template>
|
||||||
|
<div class="login-layout m-auto mt-10 sm:w-screen-xl w-full">
|
||||||
|
<div class="m-auto flex sm:flex-row flex-col sm:px-0 px-3">
|
||||||
|
<!-- 用户菜单 -->
|
||||||
|
<UserMenu :activeIndex="activeIndex" @done="onDone" class="sm:flex hidden"/>
|
||||||
|
<div class="flash bg-white rounded-lg w-full">
|
||||||
|
<div class="title text-xl text-gray-700 md:px-8 p-4 md:mt-3 font-500">修改密码</div>
|
||||||
|
<div class="sm:w-screen-md w-full sm:px-4 sm:py-2">
|
||||||
|
<Password :form="form"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-page-header>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft,View,Search } from '@element-plus/icons-vue'
|
||||||
|
import {useConfigInfo, useToken, useWebsite} from "~/composables/configState";
|
||||||
|
import useFormData from '@/utils/use-form-data';
|
||||||
|
import type {User} from '@/api/system/user/model';
|
||||||
|
import {ref} from 'vue'
|
||||||
|
import {useServerRequest} from "~/composables/useServerRequest";
|
||||||
|
import type {ApiResult} from "~/api";
|
||||||
|
import UserMenu from "./components/UserMenu.vue";
|
||||||
|
import Password from './components/Password.vue';
|
||||||
|
import type {CaptchaResult} from "~/api/passport/login/model";
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const runtimeConfig = useRuntimeConfig();
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const website = useWebsite()
|
||||||
|
const config = useConfigInfo();
|
||||||
|
const token = useToken();
|
||||||
|
const userInfo = ref<User>();
|
||||||
|
const activeIndex = ref('');
|
||||||
|
|
||||||
|
// 验证码 base64 数据
|
||||||
|
const captcha = ref('');
|
||||||
|
// 验证码内容, 实际项目去掉
|
||||||
|
const text = ref('');
|
||||||
|
// 图形验证码
|
||||||
|
const imgCode = ref('');
|
||||||
|
// 发送验证码按钮loading
|
||||||
|
const codeLoading = ref(false);
|
||||||
|
// 验证码倒计时时间
|
||||||
|
const countdownTime = ref(0);
|
||||||
|
// 验证码倒计时定时器
|
||||||
|
let countdownTimer: number | null = null;
|
||||||
|
|
||||||
|
// 配置信息
|
||||||
|
const {form, assignFields} = useFormData<User>({
|
||||||
|
userId: undefined,
|
||||||
|
nickname: '',
|
||||||
|
username: '',
|
||||||
|
phone: '',
|
||||||
|
mobile: '',
|
||||||
|
sex: '',
|
||||||
|
sexName: '',
|
||||||
|
email: '',
|
||||||
|
oldPassword: '',
|
||||||
|
password: '',
|
||||||
|
password2: '',
|
||||||
|
code: '',
|
||||||
|
smsCode: '',
|
||||||
|
comments: '',
|
||||||
|
remember: true
|
||||||
|
});
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
title: `用户中心 - ${config.value?.siteName}`,
|
||||||
|
meta: [{name: website.value.keywords, content: website.value.comments}]
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* 发送短信验证码 */
|
||||||
|
const sendCode = async () => {
|
||||||
|
if (!form.phone) {
|
||||||
|
ElMessage.error('请输入手机号码');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imgCode.value = text.value;
|
||||||
|
codeLoading.value = true;
|
||||||
|
|
||||||
|
const {data: smsCode} = await useServerRequest<ApiResult<CaptchaResult>>('/sendSmsCaptcha', {
|
||||||
|
baseURL: runtimeConfig.public.apiServer, method: "post", body: {
|
||||||
|
phone: form.phone
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (smsCode.value) {
|
||||||
|
codeLoading.value = false;
|
||||||
|
countdownTime.value = 30;
|
||||||
|
// 开始对按钮进行倒计时
|
||||||
|
countdownTimer = window.setInterval(() => {
|
||||||
|
if (countdownTime.value <= 1) {
|
||||||
|
countdownTimer && clearInterval(countdownTimer);
|
||||||
|
countdownTimer = null;
|
||||||
|
}
|
||||||
|
countdownTime.value--;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
const {data: modify} = await useServerRequest<ApiResult<User>>('/auth/password', {
|
||||||
|
baseURL: runtimeConfig.public.apiServer,
|
||||||
|
method: 'put',
|
||||||
|
body: form
|
||||||
|
})
|
||||||
|
if (modify.value?.code == 0) {
|
||||||
|
ElMessage.success('修改成功')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDone = (index: string) => {
|
||||||
|
activeIndex.value = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
// 未登录状态(是否强制登录)
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token || token == '') {
|
||||||
|
navigateTo('/passport/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const {data: response} = await useServerRequest<ApiResult<User>>('/auth/user', {baseURL: runtimeConfig.public.apiServer})
|
||||||
|
if (response.value?.data) {
|
||||||
|
userInfo.value = response.value?.data;
|
||||||
|
assignFields(response.value?.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.back(); // 返回上一页
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
(path) => {
|
||||||
|
activeIndex.value = path;
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
{immediate: true}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -11,7 +11,7 @@ export const request = <T>(url:string, options?: UseFetchOptions<T, unknown>) =>
|
|||||||
onRequest({ options }: any){
|
onRequest({ options }: any){
|
||||||
let token = ''
|
let token = ''
|
||||||
if(import.meta.client){
|
if(import.meta.client){
|
||||||
token = useToken().value
|
token = `${useToken().value}`
|
||||||
}
|
}
|
||||||
options.headers = {
|
options.headers = {
|
||||||
TenantId,
|
TenantId,
|
||||||
|
|||||||
Reference in New Issue
Block a user