update web
@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* 文章列表
|
|
||||||
*/
|
|
||||||
export function getArticleList(params: Record<string, any>) {
|
|
||||||
return request.get('article/article', params)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文章列表
|
|
||||||
*/
|
|
||||||
export function getArticleAll(params: Record<string, any>) {
|
|
||||||
return request.get('article/article/all', params)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文章详情
|
|
||||||
*/
|
|
||||||
export function getArticleDetail(id: number) {
|
|
||||||
return request.get(`article/article/${id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文章分类
|
|
||||||
*/
|
|
||||||
export function getArticleCategory() {
|
|
||||||
return request.get('article/category')
|
|
||||||
}
|
|
||||||
20
web/app.vue
@ -13,7 +13,6 @@ import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
|||||||
import en from 'element-plus/dist/locale/en.mjs'
|
import en from 'element-plus/dist/locale/en.mjs'
|
||||||
import Language from '~~/utils/language'
|
import Language from '~~/utils/language'
|
||||||
import useSystemStore from '@/stores/system'
|
import useSystemStore from '@/stores/system'
|
||||||
import useAppStore from '@/stores/app'
|
|
||||||
import useMemberStore from '@/stores/member'
|
import useMemberStore from '@/stores/member'
|
||||||
// 引入全局样式
|
// 引入全局样式
|
||||||
import '@/assets/styles/index.scss'
|
import '@/assets/styles/index.scss'
|
||||||
@ -32,22 +31,21 @@ const locale = computed(() => (systemStore.lang === 'zh-cn' ? zhCn : en))
|
|||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
configStore.getLoginConfig()
|
configStore.getLoginConfig()
|
||||||
|
|
||||||
// 查询站点信息
|
|
||||||
systemStore.getSitenfo()
|
|
||||||
|
|
||||||
// 如果已登录
|
// 如果已登录
|
||||||
getToken() && useMemberStore().setToken(getToken())
|
getToken() && useMemberStore().setToken(getToken())
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
watch(route, (nval, oval) => {
|
watch(route, (nval, oval) => {
|
||||||
useAppStore().$patch(state => {
|
// 加载语言包
|
||||||
state.route = route.path
|
const fileinfo = nval.matched[0].components.default.__file.split('/pages/')
|
||||||
})
|
const file = fileinfo[1].replace('.vue', '')
|
||||||
|
const app = fileinfo[0].substring(fileinfo[0].lastIndexOf('/') + 1)
|
||||||
|
|
||||||
|
const language = new Language(useNuxtApp().$getI18n())
|
||||||
|
language.loadLocaleMessages(app, file, useSystemStore().lang)
|
||||||
|
|
||||||
// 设置页面title
|
// 设置页面title
|
||||||
let path = route.path == '/' ? '/index' : route.path
|
let path = route.path == '/' ? '/index' : route.path
|
||||||
// 处理部署后不知道为什么url会自动拼接上 / 的问题
|
|
||||||
if (path.slice(-1) == '/') path = path.slice(0, -1)
|
|
||||||
path = !path.lastIndexOf('/') ? `${path}/index` : path
|
path = !path.lastIndexOf('/') ? `${path}/index` : path
|
||||||
let key = path.replace('/', '').replaceAll('/', '.')
|
let key = path.replace('/', '').replaceAll('/', '.')
|
||||||
|
|
||||||
@ -58,10 +56,6 @@ watch(route, (nval, oval) => {
|
|||||||
}, !oval ? 500 : 0)
|
}, !oval ? 500 : 0)
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
// 语言包初始化加载
|
|
||||||
const language = new Language(useNuxtApp().$getI18n())
|
|
||||||
language.loadLocaleMessages(route.path, useSystemStore().lang)
|
|
||||||
|
|
||||||
// 设置title模板
|
// 设置title模板
|
||||||
useHead({
|
useHead({
|
||||||
titleTemplate: (title) => {
|
titleTemplate: (title) => {
|
||||||
|
|||||||
@ -67,10 +67,3 @@ export function fetchBase64Image(data: AnyObject) {
|
|||||||
export function getCopyRight(data: AnyObject) {
|
export function getCopyRight(data: AnyObject) {
|
||||||
return request.get('copyright', data)
|
return request.get('copyright', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取站点信息
|
|
||||||
*/
|
|
||||||
export function getSiteInfo() {
|
|
||||||
return request.get('site')
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
2
web/app/lang/en/common.json
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
33
web/app/lang/zh-cn/common.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"login": "登录",
|
||||||
|
"register": "注册",
|
||||||
|
"getSmsCode": "获取短信验证码",
|
||||||
|
"smsCodeChangeText": "秒后重新获取",
|
||||||
|
"captchaTitle": "请先完成安全验证",
|
||||||
|
"confirm": "确认",
|
||||||
|
"cancel": "取消",
|
||||||
|
"captchaPlaceholder": "请输入验证码",
|
||||||
|
"mobilePlaceholder": "请输入手机号码",
|
||||||
|
"mobileError": "请输入正确的手机号",
|
||||||
|
"codePlaceholder": "请输入手机验证码",
|
||||||
|
"userAgreement": "用户协议",
|
||||||
|
"privacyAgreement": "隐私协议",
|
||||||
|
"protocolNotConfigured": "未配置协议",
|
||||||
|
"request": {
|
||||||
|
"unknownError": "未知错误",
|
||||||
|
"400": "错误的请求",
|
||||||
|
"401": "请重新登录",
|
||||||
|
"403": "拒绝访问",
|
||||||
|
"404": "请求错误",
|
||||||
|
"405": "请求方法未允许",
|
||||||
|
"408": "请求超时",
|
||||||
|
"409": "请求跨域",
|
||||||
|
"500": "服务器端出错,错误原因:",
|
||||||
|
"501": "网络未实现",
|
||||||
|
"502": "网络错误",
|
||||||
|
"503": "服务不可用",
|
||||||
|
"504": "网络超时",
|
||||||
|
"505": "http版本不支持该请求",
|
||||||
|
"timeout": "网络请求超时!"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,20 +5,12 @@
|
|||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"register": "登录",
|
"register": "注册",
|
||||||
"bind": "手机号绑定"
|
"bind": "手机号绑定"
|
||||||
},
|
},
|
||||||
"member": {
|
"member": {
|
||||||
"index": "欢迎页",
|
"index": "欢迎页",
|
||||||
"center": "个人中心"
|
"center": "个人中心"
|
||||||
},
|
|
||||||
"article": {
|
|
||||||
"list": "文章",
|
|
||||||
"detail": "文章"
|
|
||||||
},
|
|
||||||
"site": {
|
|
||||||
"close": "站点已关闭",
|
|
||||||
"nosite": "站点不存在"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getAgreementInfo } from '@/api/system'
|
import { getAgreementInfo } from '@/app/api/system'
|
||||||
|
|
||||||
const agreement = ref<any | null>(null)
|
const agreement = ref<any | null>(null)
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@ -15,14 +15,16 @@
|
|||||||
<el-form-item prop="mobile_code">
|
<el-form-item prop="mobile_code">
|
||||||
<el-input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')">
|
<el-input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key" @click="sendSmsCode" ref="smsCodeRef"></sms-code>
|
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key"
|
||||||
|
@click="sendSmsCode" ref="smsCodeRef"></sms-code>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" class="mt-[20px] w-full" size="large" @click="handleRegister" :loading="loading">{{ loading ? t('binding') : t('bind') }}</el-button>
|
<el-button type="primary" class="mt-[20px] w-full" size="large" @click="handleRegister"
|
||||||
|
:loading="loading">{{ loading ? t('binding') : t('bind') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
@ -32,8 +34,8 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, computed } from 'vue'
|
import { ref, reactive, computed } from 'vue'
|
||||||
import { bind } from '@/api/auth'
|
import { bind } from '@/app/api/auth'
|
||||||
import { bindMobile } from '@/api/member'
|
import { bindMobile } from '@/app/api/member'
|
||||||
import useMemberStore from '@/stores/member'
|
import useMemberStore from '@/stores/member'
|
||||||
import { FormInstance } from 'element-plus'
|
import { FormInstance } from 'element-plus'
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
@ -135,4 +137,4 @@ const sendSmsCode = async () => {
|
|||||||
:deep(.el-form-item__error) {
|
:deep(.el-form-item__error) {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>~/app/api/auth~/app/api/member
|
||||||
@ -7,7 +7,8 @@
|
|||||||
<div class="qrcode p-[10px] mt-[30px] border h-[120px] leading-none box-content">
|
<div class="qrcode p-[10px] mt-[30px] border h-[120px] leading-none box-content">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<el-image :src="weixinCode.url" class="w-[120px]" />
|
<el-image :src="weixinCode.url" class="w-[120px]" />
|
||||||
<div class="flex flex-col justify-center items-center absolute inset-0 bg-gray-50" v-if="weixinCode.pastDue">
|
<div class="flex flex-col justify-center items-center absolute inset-0 bg-gray-50"
|
||||||
|
v-if="weixinCode.pastDue">
|
||||||
<span class="text-xs text-gray-600">{{ weixinCode.pastDueContent }}</span>
|
<span class="text-xs text-gray-600">{{ weixinCode.pastDueContent }}</span>
|
||||||
<span @click="scanLoginFn()" class="text-xs cursor-pointer text-color mt-2">点击刷新</span>
|
<span @click="scanLoginFn()" class="text-xs cursor-pointer text-color mt-2">点击刷新</span>
|
||||||
</div>
|
</div>
|
||||||
@ -17,16 +18,19 @@
|
|||||||
|
|
||||||
<div class="bg-white w-[380px] p-[30px]">
|
<div class="bg-white w-[380px] p-[30px]">
|
||||||
<div class="flex items-end my-[30px]">
|
<div class="flex items-end my-[30px]">
|
||||||
<div class="mr-[20px] text-base cursor-pointer leading-none" :class="{ 'font-bold': type == item.type }" v-for="item in loginType" @click="type = item.type">{{item.title }}</div>
|
<div class="mr-[20px] text-base cursor-pointer leading-none" :class="{ 'font-bold': type == item.type }"
|
||||||
|
v-for="item in loginType" @click="type = item.type">{{ item.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" ref="formRef" :rules="formRules" :validate-on-rule-change="false">
|
<el-form :model="formData" ref="formRef" :rules="formRules" :validate-on-rule-change="false">
|
||||||
<div v-show="type == 'username'">
|
<div v-show="type == 'username'">
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input v-model="formData.username" :placeholder="t('usernamePlaceholder')" clearable :inline-message="true">
|
<el-input v-model="formData.username" :placeholder="t('usernamePlaceholder')" clearable
|
||||||
|
:inline-message="true">
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input v-model="formData.password" :placeholder="t('passwordPlaceholder')" type="password" clearable :show-password="true">
|
<el-input v-model="formData.password" :placeholder="t('passwordPlaceholder')" type="password"
|
||||||
|
clearable :show-password="true">
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@ -38,7 +42,8 @@
|
|||||||
<el-form-item prop="mobile_code">
|
<el-form-item prop="mobile_code">
|
||||||
<el-input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')">
|
<el-input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key" @click="sendSmsCode" ref="smsCodeRef"></sms-code>
|
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key"
|
||||||
|
@click="sendSmsCode" ref="smsCodeRef"></sms-code>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -54,7 +59,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" class="mt-[20px] w-full" size="large" @click="handleLogin" :loading="loading">{{ loading ? t('logining') : t('login') }}</el-button>
|
<el-button type="primary" class="mt-[20px] w-full" size="large" @click="handleLogin"
|
||||||
|
:loading="loading">{{ loading ? t('logining') : t('login') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div class="text-xs py-[50rpx] flex justify-center w-full" v-if="configStore.login.agreement_show">
|
<div class="text-xs py-[50rpx] flex justify-center w-full" v-if="configStore.login.agreement_show">
|
||||||
@ -77,15 +83,11 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { FormInstance } from 'element-plus'
|
import { FormInstance } from 'element-plus'
|
||||||
import { usernameLogin, mobileLogin, scanlogin, checkscan } from '@/api/auth'
|
import { usernameLogin, mobileLogin, scanlogin, checkscan } from '@/app/api/auth'
|
||||||
import useMemberStore from '@/stores/member'
|
import useMemberStore from '@/stores/member'
|
||||||
import useConfigStore from '@/stores/config'
|
import useConfigStore from '@/stores/config'
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
layout: "container"
|
|
||||||
});
|
|
||||||
|
|
||||||
// 校验二维码
|
// 校验二维码
|
||||||
const checkScanFn = (key) => {
|
const checkScanFn = (key) => {
|
||||||
let parameter = { key };
|
let parameter = { key };
|
||||||
@ -254,4 +256,4 @@ const sendSmsCode = async () => {
|
|||||||
.text-color {
|
.text-color {
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
</style>
|
</style>~/app/api/auth
|
||||||
@ -5,26 +5,32 @@
|
|||||||
<div class="title font-bold text-xl">打开手机微信</div>
|
<div class="title font-bold text-xl">打开手机微信</div>
|
||||||
<div class="tips text-sm mt-[5px]">点击右上角打开扫一扫</div>
|
<div class="tips text-sm mt-[5px]">点击右上角打开扫一扫</div>
|
||||||
<div class="qrcode mt-[30px] border leading-none">
|
<div class="qrcode mt-[30px] border leading-none">
|
||||||
<el-image :src="img('https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQHU7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAySlJSbU1Sb0hiMlQxOEcwSGhBY1AAAgTSfStkAwRYAgAA')" class="w-[120px]"></el-image>
|
<el-image
|
||||||
|
:src="img('https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQHU7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAySlJSbU1Sb0hiMlQxOEcwSGhBY1AAAgTSfStkAwRYAgAA')"
|
||||||
|
class="w-[120px]"></el-image>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white w-[380px] p-[30px]">
|
<div class="bg-white w-[380px] p-[30px]">
|
||||||
<div class="flex items-end my-[30px]">
|
<div class="flex items-end my-[30px]">
|
||||||
<div class="mr-[20px] text-base cursor-pointer leading-none" :class="{ 'font-bold': type == item.type }" v-for="item in registerType" @click="type = item.type">{{item.title }}</div>
|
<div class="mr-[20px] text-base cursor-pointer leading-none" :class="{ 'font-bold': type == item.type }"
|
||||||
|
v-for="item in registerType" @click="type = item.type">{{ item.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" ref="formRef" :rules="formRules" :validate-on-rule-change="false">
|
<el-form :model="formData" ref="formRef" :rules="formRules" :validate-on-rule-change="false">
|
||||||
<div v-show="type == 'username'">
|
<div v-show="type == 'username'">
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input v-model="formData.username" :placeholder="t('usernamePlaceholder')" clearable :inline-message="true">
|
<el-input v-model="formData.username" :placeholder="t('usernamePlaceholder')" clearable
|
||||||
|
:inline-message="true">
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input v-model="formData.password" :placeholder="t('passwordPlaceholder')" type="password" clearable :show-password="true">
|
<el-input v-model="formData.password" :placeholder="t('passwordPlaceholder')" type="password"
|
||||||
|
clearable :show-password="true">
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="confirm_password">
|
<el-form-item prop="confirm_password">
|
||||||
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')" type="password" clearable :show-password="true">
|
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')"
|
||||||
|
type="password" clearable :show-password="true">
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
@ -36,7 +42,8 @@
|
|||||||
<el-form-item prop="mobile_code">
|
<el-form-item prop="mobile_code">
|
||||||
<el-input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')">
|
<el-input v-model="formData.mobile_code" :placeholder="t('codePlaceholder')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key" @click="sendSmsCode" ref="smsCodeRef"></sms-code>
|
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key"
|
||||||
|
@click="sendSmsCode" ref="smsCodeRef"></sms-code>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -46,7 +53,8 @@
|
|||||||
<el-input v-model="formData.captcha_code" :placeholder="t('captchaPlaceholder')">
|
<el-input v-model="formData.captcha_code" :placeholder="t('captchaPlaceholder')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<div class="py-0 leading-none">
|
<div class="py-0 leading-none">
|
||||||
<el-image :src="captcha.image.value" class="h-[30px] cursor-pointer" @click="captcha.refresh()"></el-image>
|
<el-image :src="captcha.image.value" class="h-[30px] cursor-pointer"
|
||||||
|
@click="captcha.refresh()"></el-image>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
@ -60,7 +68,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" class="mt-[20px] w-full" size="large" @click="handleRegister" :loading="loading">{{ loading ? t('registering') : t('register') }}</el-button>
|
<el-button type="primary" class="mt-[20px] w-full" size="large" @click="handleRegister"
|
||||||
|
:loading="loading">{{ loading ? t('registering') : t('register') }}</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div class="text-xs py-[50rpx] flex justify-center w-full" v-if="configStore.login.agreement_show">
|
<div class="text-xs py-[50rpx] flex justify-center w-full" v-if="configStore.login.agreement_show">
|
||||||
@ -80,7 +89,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { usernameRegister, mobileRegister } from '@/api/auth'
|
import { usernameRegister, mobileRegister } from '@/app/api/auth'
|
||||||
import useMemberStore from '@/stores/member'
|
import useMemberStore from '@/stores/member'
|
||||||
import useConfigStore from '@/stores/config'
|
import useConfigStore from '@/stores/config'
|
||||||
import { FormInstance } from 'element-plus'
|
import { FormInstance } from 'element-plus'
|
||||||
@ -234,5 +243,4 @@ const sendSmsCode = async () => {
|
|||||||
|
|
||||||
:deep(.el-form-item__error) {
|
:deep(.el-form-item__error) {
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
}</style>~/app/api/auth
|
||||||
</style>
|
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<div class="flex justify-between mt-[100px]">
|
<div class="flex justify-between mt-[100px]">
|
||||||
<div class="w-[280px]">
|
<div class="w-[280px]">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/assets/images/word/course.jpg" /></div>
|
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/app/assets/images/word/course.jpg" /></div>
|
||||||
<p class="text-[20px] text-[#666] font-bold">官方教程</p>
|
<p class="text-[20px] text-[#666] font-bold">官方教程</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-[280px]">
|
<div class="w-[280px]">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/assets/images/word/api.jpg" /></div>
|
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/app/assets/images/word/api.jpg" /></div>
|
||||||
<p class="text-[20px] text-[#666] font-bold">API文档</p>
|
<p class="text-[20px] text-[#666] font-bold">API文档</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
||||||
@ -41,7 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-[280px]">
|
<div class="w-[280px]">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/assets/images/word/community.jpg" /></div>
|
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/app/assets/images/word/community.jpg" /></div>
|
||||||
<p class="text-[20px] text-[#666] font-bold">问答社区</p>
|
<p class="text-[20px] text-[#666] font-bold">问答社区</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
||||||
@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-[280px]">
|
<div class="w-[280px]">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/assets/images/word/wx.jpg"></div>
|
<div class="w-[30px] h-[30px] mr-[10px]"><img src="@/app/assets/images/word/wx.jpg"></div>
|
||||||
<p class="text-[20px] text-[#666] font-bold">关注公众号</p>
|
<p class="text-[20px] text-[#666] font-bold">关注公众号</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
<p class="text-[14px] w-[280px] h-[100px] text-[#666666] leading-[22px] mt-[30px] mb-[20px]">
|
||||||
@ -79,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.word {
|
.word {
|
||||||
background-image: url(@/assets/images/word/word-back.jpg);
|
background-image: url(@/app/assets/images/word/word-back.jpg);
|
||||||
background-size: 100%;
|
background-size: 100%;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
@ -17,7 +17,10 @@
|
|||||||
<el-table-column prop="create_time" :label="t('occurrenceTime')" />
|
<el-table-column prop="create_time" :label="t('occurrenceTime')" />
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="mt-[16px] flex justify-end">
|
<div class="mt-[16px] flex justify-end">
|
||||||
<el-pagination v-model:current-page="balanceTableData.page" v-model:page-size="balanceTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="balanceTableData.total" @size-change="loadBalanceList()" @current-change="loadBalanceList" />
|
<el-pagination v-model:current-page="balanceTableData.page"
|
||||||
|
v-model:page-size="balanceTableData.limit" layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="balanceTableData.total" @size-change="loadBalanceList()"
|
||||||
|
@current-change="loadBalanceList" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -28,7 +31,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import type { UploadProps } from 'element-plus'
|
import type { UploadProps } from 'element-plus'
|
||||||
import { getBalanceList } from '@/api/member'
|
import { getBalanceList } from '@/app/api/member'
|
||||||
// 获取会员列表
|
// 获取会员列表
|
||||||
const balanceTableData = reactive({
|
const balanceTableData = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -60,7 +63,8 @@ loadBalanceList()
|
|||||||
.box-card {
|
.box-card {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-color {
|
.text-color {
|
||||||
color: var(--jjext-color-brand);
|
color: var(--jjext-color-brand);
|
||||||
}
|
}
|
||||||
</style>
|
</style>~/app/api/member
|
||||||
@ -12,7 +12,8 @@
|
|||||||
<el-form :model="info" class="form-wrap" label-width="120px">
|
<el-form :model="info" class="form-wrap" label-width="120px">
|
||||||
<el-form-item :label="t('memberHeadimg')">
|
<el-form-item :label="t('memberHeadimg')">
|
||||||
<div class="w-full flex justify-between content-center items-center">
|
<div class="w-full flex justify-between content-center items-center">
|
||||||
<img v-if="!info.headimg" class="w-[80px] h-[80px]" src="@/assets/images/default_headimg.png" alt="">
|
<img v-if="!info.headimg" class="w-[80px] h-[80px]"
|
||||||
|
src="@/assets/images/default_headimg.png" alt="">
|
||||||
<img v-else :src="img(info.headimg)" class="w-[80px] h-[80px]" alt="">
|
<img v-else :src="img(info.headimg)" class="w-[80px] h-[80px]" alt="">
|
||||||
<el-upload class="avatar-uploader" :show-file-list="false" v-bind="upload">
|
<el-upload class="avatar-uploader" :show-file-list="false" v-bind="upload">
|
||||||
<span class="cursor-pointer text-color">{{ t('edit') }}</span>
|
<span class="cursor-pointer text-color">{{ t('edit') }}</span>
|
||||||
@ -22,7 +23,8 @@
|
|||||||
<el-form-item :label="t('nickname')">
|
<el-form-item :label="t('nickname')">
|
||||||
<div class="w-full flex justify-between content-center">
|
<div class="w-full flex justify-between content-center">
|
||||||
<span>{{ updateNickname.value }}</span>
|
<span>{{ updateNickname.value }}</span>
|
||||||
<span class="cursor-pointer text-color" @click="updateNickname.modal = true">{{ t('edit')}}</span>
|
<span class="cursor-pointer text-color" @click="updateNickname.modal = true">{{
|
||||||
|
t('edit') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -50,7 +52,7 @@
|
|||||||
import { reactive, ref, computed } from 'vue'
|
import { reactive, ref, computed } from 'vue'
|
||||||
import useMemberStore from '@/stores/member'
|
import useMemberStore from '@/stores/member'
|
||||||
import useAppStore from '@/stores/app'
|
import useAppStore from '@/stores/app'
|
||||||
import { modifyMember } from '@/api/member'
|
import { modifyMember } from '@/app/api/member'
|
||||||
import { ElMessage, UploadFile, UploadFiles } from 'element-plus'
|
import { ElMessage, UploadFile, UploadFiles } from 'element-plus'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
@ -77,7 +79,6 @@ definePageMeta({ middleware: 'auth' })
|
|||||||
const upload = computed(() => {
|
const upload = computed(() => {
|
||||||
const headers: Record<string, any> = {}
|
const headers: Record<string, any> = {}
|
||||||
headers.token = getToken()
|
headers.token = getToken()
|
||||||
headers['site-id'] = storage.get('siteId') || 1
|
|
||||||
return {
|
return {
|
||||||
action: `${request.options.baseURL}/file/image`,
|
action: `${request.options.baseURL}/file/image`,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
@ -120,4 +121,4 @@ const updateNicknameConfirm = () => {
|
|||||||
::v-deep .form-wrap .el-form-item {
|
::v-deep .form-wrap .el-form-item {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>~/app/api/member
|
||||||
@ -5,17 +5,19 @@
|
|||||||
<el-card class="box-card flex-1 ml-4" v-loading="loading" shadow="never">
|
<el-card class="box-card flex-1 ml-4" v-loading="loading" shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>{{t('welcomePage')}}</span>
|
<span>{{ t('welcomePage') }}++++++</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="px-10 py-5" v-if="info">
|
<div class="px-10 py-5" v-if="info">
|
||||||
<div class="flex items-center border-gray-300 border-b-1 pb-5 px-5">
|
<div class="flex items-center border-gray-300 border-b-1 pb-5 px-5">
|
||||||
<img v-if="!info.headimg" class="w-[65px] h-[65px] rounded-full" src="@/assets/images/default_headimg.png" alt="">
|
<img v-if="!info.headimg" class="w-[65px] h-[65px] rounded-full"
|
||||||
|
src="@/assets/images/default_headimg.png" alt="">
|
||||||
<img v-else :src="img(info.headimg)" class="w-[65px] h-[65px] rounded-full" alt="">
|
<img v-else :src="img(info.headimg)" class="w-[65px] h-[65px] rounded-full" alt="">
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
<div>
|
<div>
|
||||||
<span class="text-base font-bold">{{ info.nickname }}</span>
|
<span class="text-base font-bold">{{ info.nickname }}</span>
|
||||||
<span class="text-xs">({{t('mobile')}}:{{info.mobile ? info.mobile : t('notBound') }})</span>
|
<span class="text-xs">({{ t('mobile') }}:{{ info.mobile ? info.mobile : t('notBound')
|
||||||
|
}})</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-400 mt-1">{{ t('registrationTime') }}:{{ info.create_time }}</p>
|
<p class="text-xs text-gray-400 mt-1">{{ t('registrationTime') }}:{{ info.create_time }}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -41,6 +43,8 @@ import useMemberStore from '@/stores/member'
|
|||||||
import useAppStore from '@/stores/app'
|
import useAppStore from '@/stores/app'
|
||||||
import type { UploadProps } from 'element-plus'
|
import type { UploadProps } from 'element-plus'
|
||||||
|
|
||||||
|
definePageMeta({ middleware: 'auth' })
|
||||||
|
|
||||||
const memberStore = useMemberStore()
|
const memberStore = useMemberStore()
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const info = computed(() => {
|
const info = computed(() => {
|
||||||
@ -53,12 +57,16 @@ const appStore = useAppStore()
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
::v-deep .box-card {
|
::v-deep .box-card {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
|
|
||||||
.el-card__header {
|
.el-card__header {
|
||||||
border-color: #F1F1F1;
|
border-color: #F1F1F1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .statistic-wrap {
|
::v-deep .statistic-wrap {
|
||||||
.el-statistic__head, .el-statistic__content{
|
|
||||||
|
.el-statistic__head,
|
||||||
|
.el-statistic__content {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,7 +17,9 @@
|
|||||||
<el-table-column prop="create_time" :label="t('occurrenceTime')" />
|
<el-table-column prop="create_time" :label="t('occurrenceTime')" />
|
||||||
</el-table>
|
</el-table>
|
||||||
<div class="mt-[16px] flex justify-end">
|
<div class="mt-[16px] flex justify-end">
|
||||||
<el-pagination v-model:current-page="pointTableData.page" v-model:page-size="pointTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="pointTableData.total" @size-change="loadPointList()" @current-change="loadPointList" />
|
<el-pagination v-model:current-page="pointTableData.page" v-model:page-size="pointTableData.limit"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper" :total="pointTableData.total"
|
||||||
|
@size-change="loadPointList()" @current-change="loadPointList" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -28,7 +30,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import type { UploadProps } from 'element-plus'
|
import type { UploadProps } from 'element-plus'
|
||||||
import { getPointList } from '@/api/member'
|
import { getPointList } from '@/app/api/member'
|
||||||
// 获取会员列表
|
// 获取会员列表
|
||||||
const pointTableData = reactive({
|
const pointTableData = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -60,7 +62,7 @@ loadPointList()
|
|||||||
.box-card {
|
.box-card {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-color {
|
.text-color {
|
||||||
color: var(--jjext-color-brand);
|
color: var(--jjext-color-brand);
|
||||||
}
|
}</style>~/app/api/member
|
||||||
</style>
|
|
||||||
59
web/app/pages/routes.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
component: () => import('~/app/pages/index.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/auth/login",
|
||||||
|
component: () => import('~/app/pages/auth/login.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: "container"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/auth/register",
|
||||||
|
component: () => import('~/app/pages/auth/register.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: "container"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/auth/bind",
|
||||||
|
component: () => import('~/app/pages/auth/bind.vue'),
|
||||||
|
meta: {
|
||||||
|
layout: "container"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/auth/agreement",
|
||||||
|
component: () => import('~/app/pages/auth/agreement.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/member",
|
||||||
|
component: () => import('~/app/pages/member/index.vue'),
|
||||||
|
meta: {
|
||||||
|
middleware: ["auth"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/member/center",
|
||||||
|
component: () => import('~/app/pages/member/center.vue'),
|
||||||
|
meta: {
|
||||||
|
middleware: ["auth"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/member/balance",
|
||||||
|
component: () => import('~/app/pages/member/balance.vue'),
|
||||||
|
meta: {
|
||||||
|
middleware: ["auth"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/member/point",
|
||||||
|
component: () => import('~/app/pages/member/point.vue'),
|
||||||
|
meta: {
|
||||||
|
middleware: ["auth"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
16
web/app/router.options.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import type { RouterConfig } from '@nuxt/schema'
|
||||||
|
|
||||||
|
const routeFiles = import.meta.glob('../**/routes.ts')
|
||||||
|
const routes = []
|
||||||
|
|
||||||
|
for (const key of Object.keys(routeFiles)) {
|
||||||
|
await routeFiles[key]().then(res => {
|
||||||
|
routes.push(...res.default)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://router.vuejs.org/api/interfaces/routeroptions.html
|
||||||
|
export default <RouterConfig>{
|
||||||
|
routes: (_routes) => routes,
|
||||||
|
strict: false
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { getCaptcha } from '@/api/system'
|
import { getCaptcha } from '~/app/api/system'
|
||||||
|
|
||||||
interface formData {
|
interface formData {
|
||||||
captcha_code: string,
|
captcha_code: string,
|
||||||
|
|||||||
@ -2,10 +2,7 @@ import useAppStore from '~/stores/app'
|
|||||||
|
|
||||||
export function t(message: string) {
|
export function t(message: string) {
|
||||||
const i18n = useNuxtApp().$getI18n()
|
const i18n = useNuxtApp().$getI18n()
|
||||||
let path = useAppStore().route
|
const langKey = useAppStore().langKey
|
||||||
// 处理部署后不知道为什么url会自动拼接上 / 的问题
|
const key = `${langKey}.${message}`
|
||||||
if (path != '/' && path.slice(-1) == '/') path = path.slice(0, -1)
|
|
||||||
const file = path == '/' ? 'index' : path.replace('/', '').replaceAll('/', '.')
|
|
||||||
const key = `${file}.${message}`
|
|
||||||
return i18n.global.t(key) != key ? i18n.global.t(key) : i18n.global.t(message)
|
return i18n.global.t(key) != key ? i18n.global.t(key) : i18n.global.t(message)
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { sendSms } from '@/api/system'
|
import { sendSms } from '~/app/api/system'
|
||||||
|
|
||||||
export function useSendSms() {
|
export function useSendSms() {
|
||||||
const canGetCode = ref(true),
|
const canGetCode = ref(true),
|
||||||
|
|||||||
6
web/env/.env.dev
vendored
@ -4,17 +4,11 @@ VITE_APP_BASE_URL=''
|
|||||||
# 图片服务器地址
|
# 图片服务器地址
|
||||||
VITE_IMG_DOMAIN=''
|
VITE_IMG_DOMAIN=''
|
||||||
|
|
||||||
# 本地开发时站点id
|
|
||||||
VITE_SITE_ID = 1
|
|
||||||
|
|
||||||
# 本地存储时token的参数名
|
# 本地存储时token的参数名
|
||||||
VITE_REQUEST_STORAGE_TOKEN_KEY='webToken'
|
VITE_REQUEST_STORAGE_TOKEN_KEY='webToken'
|
||||||
|
|
||||||
# 请求时header中token的参数名
|
# 请求时header中token的参数名
|
||||||
VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
||||||
|
|
||||||
# 请求时header中站点的参数名
|
|
||||||
VITE_REQUEST_HEADER_SITEID_KEY='site-id'
|
|
||||||
|
|
||||||
# 请求时header中来源场景的参数名
|
# 请求时header中来源场景的参数名
|
||||||
VITE_REQUEST_HEADER_CHANNEL_KEY='channel'
|
VITE_REQUEST_HEADER_CHANNEL_KEY='channel'
|
||||||
6
web/env/.env.product
vendored
@ -4,17 +4,11 @@ VITE_APP_BASE_URL=''
|
|||||||
# 图片服务器地址
|
# 图片服务器地址
|
||||||
VITE_IMG_DOMAIN=''
|
VITE_IMG_DOMAIN=''
|
||||||
|
|
||||||
# 本地开发时站点id
|
|
||||||
VITE_SITE_ID = 1
|
|
||||||
|
|
||||||
# 本地存储时token的参数名
|
# 本地存储时token的参数名
|
||||||
VITE_REQUEST_STORAGE_TOKEN_KEY='webToken'
|
VITE_REQUEST_STORAGE_TOKEN_KEY='webToken'
|
||||||
|
|
||||||
# 请求时header中token的参数名
|
# 请求时header中token的参数名
|
||||||
VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
||||||
|
|
||||||
# 请求时header中站点的参数名
|
|
||||||
VITE_REQUEST_HEADER_SITEID_KEY='site-id'
|
|
||||||
|
|
||||||
# 请求时header中来源场景的参数名
|
# 请求时header中来源场景的参数名
|
||||||
VITE_REQUEST_HEADER_CHANNEL_KEY='channel'
|
VITE_REQUEST_HEADER_CHANNEL_KEY='channel'
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"title": "文章"
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"title": "文章"
|
|
||||||
}
|
|
||||||
@ -13,8 +13,6 @@
|
|||||||
"userAgreement": "用户协议",
|
"userAgreement": "用户协议",
|
||||||
"privacyAgreement": "隐私协议",
|
"privacyAgreement": "隐私协议",
|
||||||
"protocolNotConfigured": "未配置协议",
|
"protocolNotConfigured": "未配置协议",
|
||||||
"siteClose": "站点已关闭",
|
|
||||||
"noSite": "站点不存在",
|
|
||||||
"request": {
|
"request": {
|
||||||
"unknownError": "未知错误",
|
"unknownError": "未知错误",
|
||||||
"400": "错误的请求",
|
"400": "错误的请求",
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getCopyRight } from '@/api/system';
|
import { getCopyRight } from '@/app/api/system';
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
|
|
||||||
const copy = ref();
|
const copy = ref();
|
||||||
@ -48,6 +48,4 @@ const getCopy = () => {
|
|||||||
getCopy()
|
getCopy()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -9,12 +9,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mx-auto flex-shrink">
|
<div class="mx-auto flex-shrink">
|
||||||
<el-menu :default-active="appStore.route" class="h-full" mode="horizontal" :ellipsis="false" :router="true">
|
<el-menu :default-active="route.path" class="h-full" mode="horizontal" :ellipsis="false" :router="true">
|
||||||
<el-menu-item index="/" route="/">
|
<el-menu-item index="/" route="/">
|
||||||
<span class="text-base mx-4">首页</span>
|
<span class="text-base mx-4">首页</span>
|
||||||
<span></span>
|
<span></span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-menu-item index="/article/list" route="/article/list">
|
<el-menu-item index="/cms/article/list" route="/cms/article/list">
|
||||||
<span class="text-base mx-4">文章</span>
|
<span class="text-base mx-4">文章</span>
|
||||||
<span></span>
|
<span></span>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@ -42,7 +42,6 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import useMemberStore from '@/stores/member'
|
import useMemberStore from '@/stores/member'
|
||||||
import useAppStore from '@/stores/app'
|
|
||||||
|
|
||||||
const memberStore = useMemberStore()
|
const memberStore = useMemberStore()
|
||||||
const info = computed(() => memberStore.info)
|
const info = computed(() => memberStore.info)
|
||||||
@ -52,7 +51,7 @@ const logoutFn = () => {
|
|||||||
navigateTo(`/auth/login`)
|
navigateTo(`/auth/login`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const route = useRoute()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
import useSystemStore from '~/stores/system'
|
|
||||||
import Language from '~~/utils/language'
|
|
||||||
|
|
||||||
export default defineNuxtRouteMiddleware((to, from) => {
|
|
||||||
const language = new Language(useNuxtApp().$getI18n())
|
|
||||||
language.loadLocaleMessages(to.path, useSystemStore().lang)
|
|
||||||
})
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
import { loadEnv } from 'vite'
|
import { loadEnv } from 'vite'
|
||||||
|
import topLevelAwait from 'vite-plugin-top-level-await'
|
||||||
|
|
||||||
const envScript = (process.env as any).npm_lifecycle_script.split(' ')
|
const envScript = (process.env as any).npm_lifecycle_script.split(' ')
|
||||||
const envName = envScript[envScript.length - 1]
|
const envName = envScript[envScript.length - 1]
|
||||||
@ -18,6 +19,14 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
vite: {
|
vite: {
|
||||||
envDir: '~/env',
|
envDir: '~/env',
|
||||||
|
plugins: [
|
||||||
|
topLevelAwait({
|
||||||
|
// The export name of top-level await promise for each chunk module
|
||||||
|
promiseExportName: '__tla',
|
||||||
|
// The function to generate import names of top-level await promise in each chunk module
|
||||||
|
promiseImportName: i => `__tla_${i}`
|
||||||
|
})
|
||||||
|
]
|
||||||
},
|
},
|
||||||
ssr: false
|
ssr: false
|
||||||
})
|
})
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"nuxt": "^3.4.1",
|
"nuxt": "^3.4.1",
|
||||||
"nuxt-windicss": "^2.6.0",
|
"nuxt-windicss": "^2.6.0",
|
||||||
"sass": "^1.60.0",
|
"sass": "^1.60.0",
|
||||||
|
"vite-plugin-top-level-await": "^1.3.1",
|
||||||
"vue-i18n": "^9.2.2"
|
"vue-i18n": "^9.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="w-full min-h-[100%] main-container pt-5">
|
|
||||||
<div class="mt-[20px] mb-[50px]" v-if="articleDeatail">
|
|
||||||
<el-breadcrumb :separator-icon="ArrowRight">
|
|
||||||
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item :to="{ path: '/article/list' }">文章</el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item >{{ articleDeatail.category_name }}</el-breadcrumb-item>
|
|
||||||
</el-breadcrumb>
|
|
||||||
<div >
|
|
||||||
<p class="py-[20px] text-center text-[24px]">{{ articleDeatail.title }}</p>
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<!-- <div class="mr-3 flex items-center text-gray-500 text-sm text-[#999]"><el-icon><View /></el-icon> <span class="ml-1">浏览量:158</span></div> -->
|
|
||||||
<div class="mr-3 flex items-center text-gray-500 text-sm text-[#999]"><el-icon><Clock /></el-icon><span class="ml-1">时间:{{ articleDeatail.create_time }}</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[50px]" v-html="articleDeatail.content"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, reactive, computed } from 'vue'
|
|
||||||
import { getArticleDetail } from '@/api/article'
|
|
||||||
import { ArrowRight } from '@element-plus/icons-vue'
|
|
||||||
import { nMounted } from 'vue';
|
|
||||||
import { useRoute } from 'vue-router';
|
|
||||||
|
|
||||||
const Route = useRoute(); //获取到值
|
|
||||||
const articleDeatail = ref();
|
|
||||||
onMounted(() => {
|
|
||||||
obtainArticleInfo(Route.query.id)
|
|
||||||
});
|
|
||||||
|
|
||||||
const obtainArticleInfo = (id) => {
|
|
||||||
getArticleDetail(id).then(res => {
|
|
||||||
articleDeatail.value = res.data;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.index-carousel {
|
|
||||||
background-image: url('@/assets/images/index_carousel.png');
|
|
||||||
background-position: center center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-wrap{
|
|
||||||
span{
|
|
||||||
line-height: 1;
|
|
||||||
box-shadow: 0 0 5px var(--el-color-primary-light-7);
|
|
||||||
&.active{
|
|
||||||
background-image: linear-gradient(to right,var(--el-color-primary-light-5), var(--el-color-primary));
|
|
||||||
}
|
|
||||||
&:hover{
|
|
||||||
background-image: linear-gradient(to right,var(--el-color-primary-light-5), var(--el-color-primary));
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tow-line-overflow{
|
|
||||||
overflow: hidden;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
}
|
|
||||||
.text-color{
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs-label span{
|
|
||||||
font-size: 20px;
|
|
||||||
padding: 0px 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,162 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="w-full main-container pt-5">
|
|
||||||
<el-carousel height="350px" indicator-position="none" arrow="never">
|
|
||||||
<el-carousel-item>
|
|
||||||
<div class="h-full index-carousel"></div>
|
|
||||||
</el-carousel-item>
|
|
||||||
</el-carousel>
|
|
||||||
<div class="mt-[20px] mb-[50px]">
|
|
||||||
<div>
|
|
||||||
<div class="w-full">
|
|
||||||
<el-breadcrumb :separator-icon="ArrowRight">
|
|
||||||
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item :to="{ path: '/article/list' }">文章</el-breadcrumb-item>
|
|
||||||
<el-breadcrumb-item v-if="selectedCategoryName">{{ selectedCategoryName }}</el-breadcrumb-item>
|
|
||||||
</el-breadcrumb>
|
|
||||||
<div class="flex mt-[20px] items-start">
|
|
||||||
<div class="w-[50px]">类目:</div>
|
|
||||||
<el-row>
|
|
||||||
<el-button class="mb-[10px]" @click="selectedCategory(categoryItem)" v-for="(categoryItem, categoryIndex) in activeCategoryLsit" :key="categoryIndex">{{ categoryItem.name }}</el-button>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
<div class="article-list mb-[20px] cursor-pointer" v-for="(activeItem, activeIndex) in articleTableData.data" :key="activeIndex" @click="toLink(activeItem.id)">
|
|
||||||
<div class="flex justify-between relative py-[20px] border-b-1 border-gray-300 border-solid">
|
|
||||||
<div class="w-[150px] h-[150px] flex items-center">
|
|
||||||
<img :src="img(activeItem.image)"/>
|
|
||||||
</div>
|
|
||||||
<div class="w-[1030px]">
|
|
||||||
<p class="text-xl font-bold">{{ activeItem.title }}</p>
|
|
||||||
<span class="overflow-ellipsis mt-2 mb-2 tow-line-overflow text-gray-500">{{ activeItem.intro }}</span>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="activeBo flex items-right mt-2 justify-end absolute">
|
|
||||||
<span class="mr-5 text-sm text-gray-500">{{ activeItem.create_time }}</span>
|
|
||||||
<div class="mr-3 flex items-center text-gray-500 text-sm"><el-icon><View /></el-icon> <span class="ml-1">158</span></div>
|
|
||||||
<div class="mr-3 flex items-center text-gray-500 text-sm"><el-icon><Pointer /></el-icon> <span class="ml-1">22</span></div>
|
|
||||||
<div class="mr-3 flex items-center text-gray-500 text-sm"><el-icon><Star /></el-icon> <span class="ml-1">55</span></div>
|
|
||||||
<div class="flex items-center text-gray-500 text-sm"><el-icon><ChatDotRound /></el-icon> <span class="ml-1">655</span></div>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<el-pagination
|
|
||||||
class="justify-center"
|
|
||||||
@current-change="handleCurrentChange"
|
|
||||||
@size-change="handleSizeChange"
|
|
||||||
:page-size="articleTableData.limit"
|
|
||||||
background
|
|
||||||
layout="prev, pager, next"
|
|
||||||
:total="articleTableData.total"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, reactive } from 'vue'
|
|
||||||
import { getArticleCategory,getArticleList } from '@/api/article'
|
|
||||||
import { ArrowRight } from '@element-plus/icons-vue'
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const activeCategoryLsit = ref([])
|
|
||||||
const selectedCategoryName = ref()
|
|
||||||
const articleTableData = reactive({
|
|
||||||
page: 1,
|
|
||||||
limit: 10,
|
|
||||||
total: 0,
|
|
||||||
loading: true,
|
|
||||||
data: [],
|
|
||||||
searchParam: {
|
|
||||||
title: '',
|
|
||||||
category_id:''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文章列表
|
|
||||||
*/
|
|
||||||
const loadArticleList = (page: number = 1) => {
|
|
||||||
articleTableData.loading = true
|
|
||||||
articleTableData.page = page
|
|
||||||
|
|
||||||
getArticleList({
|
|
||||||
page: articleTableData.page,
|
|
||||||
limit: articleTableData.limit,
|
|
||||||
...articleTableData.searchParam
|
|
||||||
}).then(res => {
|
|
||||||
articleTableData.loading = false
|
|
||||||
articleTableData.data = res.data.data
|
|
||||||
articleTableData.total = res.data.total
|
|
||||||
}).catch(() => {
|
|
||||||
articleTableData.loading = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
loadArticleList()
|
|
||||||
|
|
||||||
const checkArticleCategory = () => {
|
|
||||||
getArticleCategory().then(res => {
|
|
||||||
activeCategoryLsit.value = res.data.data;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
checkArticleCategory()
|
|
||||||
|
|
||||||
const selectedCategory = (item) => {
|
|
||||||
articleTableData.searchParam.category_id = item.category_id;
|
|
||||||
selectedCategoryName.value = item.name
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSizeChange = (val: number) => {
|
|
||||||
loadArticleList(val)
|
|
||||||
}
|
|
||||||
const handleCurrentChange = (val: number) => {
|
|
||||||
loadArticleList(val)
|
|
||||||
}
|
|
||||||
const toLink = (id) => {
|
|
||||||
router.push(`/article/detail?id=${id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.index-carousel {
|
|
||||||
background-image: url('@/assets/images/index_carousel.png');
|
|
||||||
background-position: center center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-wrap{
|
|
||||||
span{
|
|
||||||
line-height: 1;
|
|
||||||
box-shadow: 0 0 5px var(--el-color-primary-light-7);
|
|
||||||
&.active{
|
|
||||||
background-image: linear-gradient(to right,var(--el-color-primary-light-5), var(--el-color-primary));
|
|
||||||
}
|
|
||||||
&:hover{
|
|
||||||
background-image: linear-gradient(to right,var(--el-color-primary-light-5), var(--el-color-primary));
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tow-line-overflow{
|
|
||||||
overflow: hidden;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
}
|
|
||||||
.text-color{
|
|
||||||
color: var(--el-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-tabs-label span{
|
|
||||||
font-size: 20px;
|
|
||||||
padding: 0px 10px;
|
|
||||||
}
|
|
||||||
.activeBo {
|
|
||||||
bottom : 20px;
|
|
||||||
right : 0px
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -2,15 +2,13 @@ import { createI18n } from 'vue-i18n'
|
|||||||
|
|
||||||
import zhCn from "~/lang/zh-cn/common.json";
|
import zhCn from "~/lang/zh-cn/common.json";
|
||||||
import en from "~/lang/en/common.json"
|
import en from "~/lang/en/common.json"
|
||||||
import zhCnPages from "~/lang/zh-cn/pages.json";
|
|
||||||
import enPages from "~/lang/en/pages.json"
|
|
||||||
|
|
||||||
export default defineNuxtPlugin((NuxtApp) => {
|
export default defineNuxtPlugin((NuxtApp) => {
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
globalInjection: true, //是否全局注入
|
globalInjection: true, //是否全局注入
|
||||||
messages: {
|
messages: {
|
||||||
"zh-cn": Object.assign(zhCn, zhCnPages),
|
"zh-cn": zhCn,
|
||||||
"en": Object.assign(en, enPages)
|
"en": en
|
||||||
},
|
},
|
||||||
silentFallbackWarn: true,
|
silentFallbackWarn: true,
|
||||||
silentTranslationWarn: true
|
silentTranslationWarn: true
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
interface App {
|
interface App {
|
||||||
route: string
|
langKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const useAppStore = defineStore('app', {
|
const useAppStore = defineStore('app', {
|
||||||
state: (): App => {
|
state: (): App => {
|
||||||
return {
|
return {
|
||||||
route: ''
|
langKey: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { getConfig } from '@/api/auth'
|
import { getConfig } from '~/app/api/auth'
|
||||||
|
|
||||||
interface loginConfig {
|
interface loginConfig {
|
||||||
is_username: number | boolean,
|
is_username: number | boolean,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { getMemberInfo } from '@/api/member'
|
import { getMemberInfo } from '~/app/api/member'
|
||||||
import { logout } from '@/api/auth'
|
import { logout } from '~/app/api/auth'
|
||||||
|
|
||||||
interface Member {
|
interface Member {
|
||||||
token: string | null
|
token: string | null
|
||||||
@ -21,6 +21,7 @@ const useMemberStore = defineStore('member', {
|
|||||||
await this.getMemberInfo()
|
await this.getMemberInfo()
|
||||||
},
|
},
|
||||||
async getMemberInfo() {
|
async getMemberInfo() {
|
||||||
|
if (!this.token) return
|
||||||
await getMemberInfo()
|
await getMemberInfo()
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
this.info = res.data
|
this.info = res.data
|
||||||
@ -30,6 +31,7 @@ const useMemberStore = defineStore('member', {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
logout() {
|
logout() {
|
||||||
|
if (!this.token) return
|
||||||
logout().then(() => {
|
logout().then(() => {
|
||||||
this.$reset()
|
this.$reset()
|
||||||
useCookie('token').value = null
|
useCookie('token').value = null
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import storage from '@/utils/storage'
|
import storage from '@/utils/storage'
|
||||||
import { getSiteInfo } from '@/api/system'
|
|
||||||
|
|
||||||
interface System {
|
interface System {
|
||||||
lang: string,
|
lang: string,
|
||||||
@ -18,16 +17,7 @@ const useSystemStore = defineStore('system', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async getSitenfo() {
|
|
||||||
await getSiteInfo()
|
|
||||||
.then((res: any) => {
|
|
||||||
this.site = res.data
|
|
||||||
if (this.site.status == 3) navigateTo('/site/close', { replace: true })
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
navigateTo('/site/nosite', { replace: true })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { nextTick } from 'vue'
|
import { nextTick } from 'vue'
|
||||||
|
import useAppStore from '~/stores/app'
|
||||||
|
|
||||||
class Language {
|
class Language {
|
||||||
private i18n: any;
|
private i18n: any;
|
||||||
@ -28,27 +29,41 @@ class Language {
|
|||||||
* @param locale
|
* @param locale
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async loadLocaleMessages(path: string, locale: string) {
|
public async loadLocaleMessages(app: string, path: string, locale: string) {
|
||||||
try {
|
try {
|
||||||
const file = path == '/' ? 'index' : path.replace('/', '').replaceAll('/', '.')
|
const file = path.replaceAll('/', '.')
|
||||||
|
|
||||||
if (this.loadLocale.includes(`${locale}/${file}`)) {
|
if (this.loadLocale.includes(`${app}/${locale}/${file}`)) {
|
||||||
return nextTick()
|
return nextTick()
|
||||||
}
|
}
|
||||||
this.loadLocale.push(`${locale}/${file}`)
|
|
||||||
|
// 加载pages语言包
|
||||||
|
if (!this.loadLocale.includes(`${app}/${locale}/pages`)) {
|
||||||
|
// 引入语言包文件
|
||||||
|
const pagesMessages = await import(`@/${app}/lang/${locale}/pages.json`)
|
||||||
|
this.i18n.global.mergeLocaleMessage(locale, pagesMessages.default)
|
||||||
|
this.loadLocale.push(`${app}/${locale}/pages`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadLocale.push(`${app}/${locale}/${file}`)
|
||||||
|
|
||||||
// 引入语言包文件
|
// 引入语言包文件
|
||||||
const messages = await import(`~/lang/${locale}/${file}.json`)
|
const messages = await import(`@/${app}/lang/${locale}/${file}.json`)
|
||||||
|
|
||||||
let data: Record<string, string> = {}
|
let data: Record<string, string> = {}
|
||||||
Object.keys(messages.default).forEach(key => {
|
Object.keys(messages.default).forEach(key => {
|
||||||
data[`${file}.${key}`] = messages.default[key]
|
data[`${app}.${file}.${key}`] = messages.default[key]
|
||||||
|
})
|
||||||
|
|
||||||
|
useAppStore().$patch(state => {
|
||||||
|
state.langKey = `${app}.${file}`
|
||||||
})
|
})
|
||||||
|
|
||||||
this.i18n.global.mergeLocaleMessage(locale, data)
|
this.i18n.global.mergeLocaleMessage(locale, data)
|
||||||
this.setI18nLanguage(locale)
|
this.setI18nLanguage(locale)
|
||||||
return nextTick()
|
return nextTick()
|
||||||
} catch {
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
this.setI18nLanguage(locale)
|
this.setI18nLanguage(locale)
|
||||||
return nextTick()
|
return nextTick()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,6 @@ class Http {
|
|||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
|
|
||||||
this.options.baseURL = runtimeConfig.public.VITE_APP_BASE_URL || `${location.origin}/api/`
|
this.options.baseURL = runtimeConfig.public.VITE_APP_BASE_URL || `${location.origin}/api/`
|
||||||
this.options.headers[runtimeConfig.public.VITE_REQUEST_HEADER_SITEID_KEY] = useCookie('siteId').value || runtimeConfig.public.VITE_SITE_ID
|
|
||||||
this.options.headers[runtimeConfig.public.VITE_REQUEST_HEADER_CHANNEL_KEY] = 'pc'
|
this.options.headers[runtimeConfig.public.VITE_REQUEST_HEADER_CHANNEL_KEY] = 'pc'
|
||||||
if (getToken()) this.options.headers[runtimeConfig.public.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
|
if (getToken()) this.options.headers[runtimeConfig.public.VITE_REQUEST_HEADER_TOKEN_KEY] = getToken()
|
||||||
}
|
}
|
||||||
|
|||||||