This commit is contained in:
全栈小学生 2024-12-12 18:28:08 +08:00
parent 5457b86e0a
commit 319aa2a6db
59 changed files with 3198 additions and 1527 deletions

View File

@ -189,4 +189,4 @@ export function changeTemplate(params: Record<string, any>) {
*/
export function getApps(params: Record<string, any>) {
return request.get(`diy/apps`)
}
}

174
admin/src/app/api/web.ts Normal file
View File

@ -0,0 +1,174 @@
import request from '@/utils/request'
/**
* PC导航管理列表
* @param params
* @returns
*/
export function getNavList(params: Record<string, any>) {
return request.get(`web/nav`, {params})
}
/**
* PC导航管理详情
* @param id PC导航管理id
* @returns
*/
export function getNavInfo(id: number) {
return request.get(`web/nav/${id}`);
}
/**
* PC导航管理
* @param params
* @returns
*/
export function addNav(params: Record<string, any>) {
return request.post('web/nav', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
* PC导航管理
* @param params
* @returns
*/
export function editNav(params: Record<string, any>) {
return request.put(`web/nav/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param params
*/
export function editNavSort(params: Record<string, any>) {
return request.put(`web/nav/sort`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
* PC导航管理
* @param id
* @returns
*/
export function deleteNav(id: number) {
return request.delete(`web/nav/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
/**
* PC端自定义链接列表
* @param params
*/
export function getLink(params: Record<string, any>) {
return request.get(`web/link`, { params })
}
/**
*
* @param params
* @returns
*/
export function getFriendlyLinkList(params: Record<string, any>) {
return request.get(`web/friendly_link`, {params})
}
/**
*
* @param id id
* @returns
*/
export function getFriendlyLinkInfo(id: number) {
return request.get(`web/friendly_link/${id}`);
}
/**
*
* @param params
* @returns
*/
export function addFriendlyLink(params: Record<string, any>) {
return request.post('web/friendly_link', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param params
* @returns
*/
export function editFriendlyLink(params: Record<string, any>) {
return request.put(`web/friendly_link/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param id
* @returns
*/
export function deleteFriendlyLink(id: number) {
return request.delete(`web/friendly_link/${id}`, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param params
*/
export function editFriendlyLinkSort(params: Record<string, any>) {
return request.put(`web/friendly_link/sort`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
* 广
* @param params
* @returns
*/
export function getAvdPositionList(params: Record<string, any>) {
return request.get(`web/adv_position`, { params })
}
/**
* 广
* @param params
* @returns
*/
export function getAdvList(params: Record<string, any>) {
return request.get(`web/adv`, { params })
}
/**
* 广
* @param id
* @returns
*/
export function deleteAdv(id: number) {
return request.delete(`web/adv/${ id }`, { showSuccessMessage: true })
}
/**
* 广
* @param params
* @returns
*/
export function addAdv(params: Record<string, any>) {
return request.post('web/adv', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
* 广
* @param params
* @returns
*/
export function editAdv(params: Record<string, any>) {
return request.put(`web/adv/${ params.adv_id }`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
*
* @param params
*/
export function editAdvSort(params: Record<string, any>) {
return request.put(`web/adv/sort`, params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
* 广
* @param id id
* @returns
*/
export function getAdvInfo(id: number) {
return request.get(`web/adv/${ id }`);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -62,6 +62,8 @@
"imageUpload": "图片上传",
"imageSet": "图片设置",
"imageAdsTips": "建议上传尺寸相同的图片推荐尺寸750*350",
"imageAdsSameScreenTips": "开启沉浸式样式,请确保该图片广告组件在页面中位于最顶端;为保证体验,请不要开导航栏;沉浸式样式仅在微信小程序中生效。",
"sameScreen": "沉浸式",
"addImageAd": "添加图片",
"imageUrlTip": "请上传图片",
"imageHeight": "图片高度",

View File

@ -29,8 +29,8 @@
"detaBirth": "出生日期",
"sex": "性别",
"wxUnionid": "微信unionid",
"weappOpenid": "微信用户openid",
"wxOpenid": "微信小程序openid",
"weappOpenid": "微信小程序openid",
"wxOpenid": "微信用户openid",
"head": "会员头像",
"username": "用户名",
"usernamePlaceholder": "请输入用户名",

View File

@ -13,9 +13,9 @@
"mchId": "商户号",
"mchIdPlaceholder": "请输入商户号",
"mchIdTips": "微信支付商户号MCHID",
"mchSecretKey": "API密钥",
"mchSecretKeyPlaceholder": "请输入API密钥",
"mchSecretKeyTips": "微信支付商户API密钥paySignKey",
"mchSecretKey": "APIv3密钥",
"mchSecretKeyPlaceholder": "请输入APIv3密钥",
"mchSecretKeyTips": "微信支付商户APIv3密钥paySignKey",
"mchSecretCert": "商户私钥",
"mchSecretCertPlaceholder": "请上传商户私钥",
"mchSecretCertTips": "微信支付API证书apiclient_key.pem",

View File

@ -4,9 +4,9 @@
"mchId": "商户号",
"mchIdPlaceholder": "请输入商户号",
"mchIdTips": "微信支付商户号MCHID",
"mchSecretKey": "API密钥",
"mchSecretKeyPlaceholder": "请输入API密钥",
"mchSecretKeyTips": "微信支付商户API密钥paySignKey",
"mchSecretKey": "APIv3密钥",
"mchSecretKeyPlaceholder": "请输入APIv3密钥",
"mchSecretKeyTips": "微信支付商户APIv3密钥paySignKey",
"mchSecretCert": "商户私钥",
"mchSecretCertPlaceholder": "请上传商户私钥",
"mchSecretCertTips": "微信支付API证书apiclient_key.pem",
@ -28,4 +28,4 @@
"alipayPublicCertPathTips": "上传alipayCertPublicKey文件",
"alipayRootCertPathTips": "上传alipayRootCert文件",
"operationTip": "温馨提示:打款设置用于会员提现转账,发放红包等场景"
}
}

View File

@ -0,0 +1,16 @@
{
"addAdv": "添加广告",
"updateAdv": "编辑广告",
"advName": "广告名称",
"advNamePlaceholder": "请输入广告位名称",
"advPosition": "所属广告位",
"advUrl": "广告链接",
"advUrlPlaceholder": "请选择链接地址",
"advImg": "广告图片",
"advImagePlaceholder": "请上传广告图片",
"background": "背景色",
"sort": "排序号",
"sortPlaceholder": "请输入排序号",
"sortTips": "排序号格式输入错误",
"advDeleteTips": "确定要删除该数据吗?"
}

View File

@ -0,0 +1,6 @@
{
"apName": "广告位名称",
"keywords": "广告关键字",
"operation": "操作",
"manageAdv": "管理广告"
}

View File

@ -0,0 +1,19 @@
{
"linkPic": "图片",
"linkPicPlaceholder": "请输入图片",
"linkTitle": "标题",
"linkTitlePlaceholder": "请输入标题",
"linkUrl": "链接",
"linkUrlPlaceholder": "请输入链接",
"sort": "排序号",
"sortPlaceholder": "请输入排序号",
"sortTips": "排序号格式输入错误",
"isShow": "是否显示",
"isShowPlaceholder": "请输入是否显示",
"addFriendlyLink": "添加友情链接",
"updateFriendlyLink": "编辑友情链接",
"friendlyLinkDeleteTips": "确定要删除该数据吗?",
"startDate": "请选择开始时间",
"endDate": "请选择结束时间",
"addressTips": "链接格式错误"
}

View File

@ -0,0 +1,15 @@
{
"navTitle": "导航名称",
"navTitlePlaceholder": "请输入导航名称",
"navUrl": "链接地址",
"navUrlPlaceholder": "请选择链接地址",
"sort": "排序号",
"sortPlaceholder": "请输入排序号",
"sortTips": "排序号格式输入错误",
"isBlank": "新窗口打开",
"createTime": "创建时间",
"isShow": "是否显示",
"addNav": "添加导航",
"updateNav": "编辑导航",
"navDeleteTips": "确定要删除该数据吗?"
}

View File

@ -77,7 +77,7 @@
</el-form-item>
<el-form-item :label="t('sort')">
<el-input-number v-model="formData.sort" :min="0" max="99999999" />
<el-input-number v-model="formData.sort" :min="0" max="8" />
</el-form-item>
</el-form>

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="150px" ref="formRef" v-loading="loading">
@ -98,6 +98,9 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/channel/aliapp')
}
const loading = ref(true)

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
@ -99,6 +99,9 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const back = () => {
router.push('/channel/aliapp')
}
const pageName = route.meta.title
const loading = ref(true)
const formData = reactive<Record<string, string>>({

View File

@ -22,7 +22,7 @@
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
</template>
</el-input>
<span class="ml-2 cursor-pointer visit-btn">{{t('clickVisit')}}</span>
<span class="ml-2 cursor-pointer visit-btn" @click="visitFn">{{t('clickVisit')}}</span>
</el-form-item>
</el-form>
</el-card>

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="170px" ref="formRef" :rules="formRules" v-loading="loading">
@ -139,7 +139,9 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/channel/weapp')
}
const loading = ref(true)
const formData = reactive<Record<string, any>>({

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
@ -63,7 +63,9 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/channel/weapp')
}
const linkEvent = () => {
window.open('https://mp.weixin.qq.com/', '_blank')
}

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="150px" ref="formRef" :rules="formRules" v-loading="loading">
@ -129,7 +129,9 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/channel/wechat')
}
const loading = ref(true)
const formData = reactive<Record<string, any>>({

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] pt-[20px] !border-none" shadow="never">
@ -60,6 +60,9 @@ import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const router = useRouter()
const back = () => {
router.push('/channel/wechat')
}
const loading = ref(true)
const formData = reactive<Record<string, string>>({
wechat_name: '',

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-form class="page-form mt-[15px]" :model="formData" label-width="150px" ref="formRef" :rules="formRules" v-loading="loading">
@ -92,6 +92,10 @@ import NewsCard from '@/app/views/channel/wechat/components/news-card.vue'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/channel/wechat/reply')
}
const showDialog = ref(false)
const formData: any = reactive({

View File

@ -185,6 +185,12 @@
<el-radio :label="'italics'">{{t('btnTextItalics')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>

View File

@ -94,7 +94,7 @@ import { img } from '@/utils/common'
import { range } from 'lodash-es'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['pageBgColor','marginTop','marginBottom','marginBoth'] //
diyStore.editComponent.ignore = ['pageBgColor','marginTop','marginBottom','marginBoth','componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {
@ -222,5 +222,5 @@ defineExpose({})
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@ -38,7 +38,7 @@ import useDiyStore from '@/stores/modules/diy'
import { img } from '@/utils/common'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
diyStore.editComponent.ignore = ['componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {

View File

@ -4,6 +4,11 @@
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('imageSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('sameScreen')" v-if="diyStore.currentIndex == 0">
<el-switch v-model="diyStore.editComponent.isSameScreen" />
<div class="text-sm text-gray-400 leading-[1.4]">{{ t('imageAdsSameScreenTips') }}</div>
</el-form-item>
<el-form-item :label="t('imageHeight')" class="display-block">
<el-input v-model.trim="diyStore.editComponent.imageHeight" :placeholder="t('imageHeightPlaceholder')" clearable maxlength="10" @blur="blurImageHeight">
@ -52,7 +57,7 @@ import { range } from 'lodash-es'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
diyStore.editComponent.ignore = ['componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {

View File

@ -102,9 +102,31 @@ const changeStyle = (item:any) => {
const confirmStyle = () => {
diyStore.editComponent.styleName = selectStyle.title;
diyStore.editComponent.style = selectStyle.value;
initStyle(diyStore.editComponent.style);
showDialog.value = false
}
const initStyle = (style: any) => {
if (style == 'style-1') {
diyStore.editComponent.bottomRounded = 0;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-2') {
diyStore.editComponent.bottomRounded = 0;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-3') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-4') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-5') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
}
}
defineExpose({})
</script>

View File

@ -8,7 +8,7 @@
<el-form-item :label="t('image')">
<upload-image v-model="diyStore.editComponent.moduleOne.head.textImg" :limit="1"/>
</el-form-item>
<el-form-item :label="t('subTitle')">
<el-input v-model.trim="diyStore.editComponent.moduleOne.head.subText" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
</el-form-item>
@ -125,7 +125,7 @@ import { img } from '@/utils/common'
import { ref, reactive } from 'vue'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
diyStore.editComponent.ignore = ['componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {

View File

@ -129,6 +129,7 @@ import { t } from '@/lang'
import { getApps,getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare, setUseDiyPage } from '@/app/api/diy'
import { ElMessageBox, FormInstance } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { setTablePageStorage,getTablePageStorage } from "@/utils/common";
const route = useRoute()
const router = useRouter()
@ -234,12 +235,13 @@ const loadDiyPageList = (page: number = 1) => {
diyPageTableData.loading = false
diyPageTableData.data = res.data.data
diyPageTableData.total = res.data.total
setTablePageStorage(diyPageTableData.page, diyPageTableData.limit, diyPageTableData.searchParam);
}).catch(() => {
diyPageTableData.loading = false
})
}
loadDiyPageList()
loadDiyPageList(getTablePageStorage(diyPageTableData.searchParam).page);
//
const editEvent = (data: any) => {

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never" v-loading="loading">

View File

@ -89,6 +89,7 @@ const setFormData = async (row: any = null) => {
const getRefundListInfo = async (no) => {
loading.value = true
formData.value = null
refundList.value = [];
await getPayRefundInfo(no).then(({ data }) => {
formData.value = data
refundList.value.push(data)

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none relative" shadow="never" v-if="formData">
@ -66,6 +66,9 @@ import { ArrowLeft } from '@element-plus/icons-vue'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/finance/refund')
}
const refundNo: any = route.query.refund_no
const loading = ref(true)

View File

@ -18,7 +18,7 @@
</el-card>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
<el-button type="primary" :loading="loading" @click="submitForm(formRef)">{{ t('save') }}</el-button>
</div>
</div>
</div>

View File

@ -1,9 +1,9 @@
<template>
<el-container :class="['w-full h-screen bg-page flex flex-col']">
<el-container :class="['w-full h-screen bg-page flex flex-col','login-wrap']">
<template v-if="!imgLoading">
<!-- 平台端登录 -->
<el-main class="login-main items-center justify-center">
<div class="flex rounded-2xl overflow-hidden">
<el-main class="login-main items-center justify-center flex-1 h-0">
<div class="flex rounded-2xl shadow overflow-hidden">
<div class="login-main-left w-[450px] flex flex-wrap justify-center">
<el-image v-if="loginConfig.bg" class="w-[450px] h-[400px]" :src="img(loginConfig.bg)" fit="cover" />
<img v-else src="@/app/assets/images/login/niushop_login_index_left.jpg" alt="">
@ -11,29 +11,17 @@
<div class="login flex flex-col w-[400px] h-[400px] p-[40px]">
<h3 class="text-center text-lg font-bold mb-[10px]">{{ webSite.site_name || t('siteTitle') }}</h3>
<h3 class="text-center text-2xl font-bold mb-[26px]">{{ t('platform') }}</h3>
<el-form :model="form" ref="formRef" :rules="formRules">
<el-form :model="form" ref="formRef" :rules="formRules" class="mt-[30px]">
<el-form-item prop="username">
<el-input v-model="form.username" :placeholder="t('userPlaceholder')"
@keyup.enter="handleLogin(formRef)" class="h-[40px] input-with-select">
<template #prepend>
<icon name="element User" />
</template>
</el-input>
<el-input v-model.trim="form.username" :placeholder="t('userPlaceholder')" autocomplete="off" @keyup.enter="handleLogin(formRef)" class="h-[40px]"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="form.password" :placeholder="t('passwordPlaceholder')" type="password"
@keyup.enter="handleLogin(formRef)" :show-password="true"
class="h-[40px] input-with-select">
<template #prepend>
<icon name="element Lock" />
</template>
</el-input>
<el-input v-model.trim="form.password" :placeholder="t('passwordPlaceholder')" type="password" autocomplete="new-password" @keyup.enter="handleLogin(formRef)" :show-password="true" class="h-[40px]"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" class="mt-[30px] h-[40px] w-full" @click="handleLogin(formRef)" :loading="loading">{{ loading ? t('logging') : t('login') }}</el-button>
<el-button type="primary" class="mt-[30px] !h-[40px] w-full" @click="handleLogin(formRef)" :loading="loading">{{ loading ? t('logging') : t('login') }}</el-button>
</el-form-item>
</el-form>
@ -41,24 +29,22 @@
</div>
</el-main>
<div class="flex items-center justify-center mt-[20px] text-[#999] text-sm pb-8" v-if="copyright">
<a :href="copyright.gov_url" v-if="copyright.gov_record" class="flex" target="_blank">
<img src="@/app/assets/images/gov_icon.png" alt="" class="h-[20px] mr-1">
<span class="mr-3">公安备案号:{{ copyright.gov_record }}</span>
</a>
<a href="https://beian.miit.gov.cn/" target="_blank" v-if="copyright.icp">
<span class="mr-3">备案号:{{ copyright.icp }}</span>
</a>
<div class="flex items-center justify-center mt-[20px] pb-[20px] text-sm text-[#999]" v-if="copyright">
<a :href="copyright.copyright_link" target="_blank">
<span class="mr-3" v-if="copyright.copyright_desc">{{ copyright.copyright_desc }}</span>
<span class="mr-3" v-if="copyright.company_name">{{ copyright.company_name }}</span>
<span class="mr-3" v-if="copyright.copyright_desc">©{{ copyright.copyright_desc }}</span>
</a>
<a href="https://beian.miit.gov.cn/" v-if="copyright.icp" target="_blank">
<span class="mr-3">{{ copyright.icp }}</span>
</a>
<a :href="copyright.gov_url" v-if="copyright.gov_record" target="_blank">
<span class="mr-3">{{ copyright.gov_record }}</span>
</a>
</div>
</template>
<!-- 验证组件 -->
<verify @success="success" :mode="pop" captchaType="blockPuzzle" :imgSize="{ width: '330px', height: '155px' }"
ref="verifyRef"></verify>
<verify @success="success" :mode="pop" captchaType="blockPuzzle" :imgSize="{ width: '330px', height: '155px' }" ref="verifyRef"></verify>
</el-container>
</template>
@ -67,7 +53,6 @@ import { inject, reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { t } from '@/lang'
import storage from '@/utils/storage'
import { getLoginConfig } from '@/app/api/auth'
import useUserStore from '@/stores/modules/user'
import { setWindowTitle, img } from '@/utils/common'
@ -154,33 +139,21 @@ const loginFn = (data = {}) => {
<style lang="scss">
.login-wrap {
background-image: url("@/app/assets/images/login/login_index_bg.png");
background-image: url("@/app/assets/images/login/login_index_bg.jpg");
background-repeat: no-repeat;
background-size: cover;
}
.login-site-main {
padding: 0 !important;
}
.input-with-select .el-input-group__prepend {
background-color: var(--el-fill-color-blank);
padding: 0 15px;
}
.login-main {
display: flex !important;
}
.login {
background: var(--el-bg-color);
}
.login {
background: var(--el-bg-color);
}
.admin_name {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
.el-form-item__error {
top : 45px;
}
}
@media only screen and (max-width: 750px) {

View File

@ -3,7 +3,7 @@
<div class="main-container" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
@ -101,6 +101,9 @@ import useAppStore from '@/stores/modules/app'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/marketing/verify')
}
const appStore = useAppStore()
const loading = ref(true)

View File

@ -8,7 +8,7 @@
<el-input v-model.trim="formData.memo" type="textarea" rows="4" clearable :placeholder="t('memoPlaceholder')" class="input-width" maxlength="200" show-word-limit />
</el-form-item>
<el-form-item :label="t('sort')" prop="sort">
<el-input v-model.trim="formData.sort" clearable maxlength="6" show-word-limit :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
<el-input v-model.trim="formData.sort" clearable maxlength="8" show-word-limit :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
</el-form-item>
</el-form>

View File

@ -73,6 +73,7 @@ import { t } from '@/lang'
import { getMemberLevelPageList, deleteMemberLevel } from '@/app/api/member'
import { ElMessageBox, FormInstance } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { setTablePageStorage,getTablePageStorage } from "@/utils/common";
const route = useRoute()
const router = useRouter()
@ -112,11 +113,12 @@ const loadMemberLevelList = (page: number = 1) => {
memberLevelTableData.loading = false
memberLevelTableData.data = res.data.data
memberLevelTableData.total = res.data.total
setTablePageStorage(memberLevelTableData.page, memberLevelTableData.limit, memberLevelTableData.searchParam);
}).catch(() => {
memberLevelTableData.loading = false
})
}
loadMemberLevelList()
loadMemberLevelList(getTablePageStorage(memberLevelTableData.searchParam).page);
/**
* 添加会员标签

View File

@ -3,7 +3,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never" v-loading="loading">
@ -28,12 +28,12 @@
<h3 class="panel-title !text-sm">{{ t('levelBenefits') }}</h3>
<div class="pl-[100px]">
<member-benefits ref="benefitsRef" v-model="formData.level_benefits"/>
<member-benefits v-if="!loading" ref="benefitsRef" v-model="formData.level_benefits"/>
</div>
<h3 class="panel-title !text-sm">{{ t('levelGift') }}</h3>
<div class="pl-[100px]">
<member-gift ref="giftRef" v-model="formData.level_gifts"/>
<member-gift v-if="!loading" ref="giftRef" v-model="formData.level_gifts"/>
</div>
</el-card>
@ -61,6 +61,10 @@ const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/member/level')
}
const benefitsRef = ref(null)
const giftRef = ref(null)
const loading = ref(true)

View File

@ -104,7 +104,7 @@ import { t } from '@/lang'
import { ElMessageBox, FormInstance } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { getPosterPageList,getPosterType,modifyPosterStatus,modifyPosterDefault,deletePoster,getPreviewPoster } from '@/app/api/poster'
import { img } from '@/utils/common'
import { img,setTablePageStorage,getTablePageStorage } from '@/utils/common'
const router = useRouter()
const route = useRoute()
@ -192,12 +192,13 @@ const loadPosterPageList = (page: number = 1) => {
posterTableData.loading = false
posterTableData.data = res.data.data
posterTableData.total = res.data.total
setTablePageStorage(posterTableData.page, posterTableData.limit, posterTableData.searchParam);
}).catch(() => {
posterTableData.loading = false
})
}
loadPosterPageList()
loadPosterPageList(getTablePageStorage(posterTableData.searchParam).page);
//
const editEvent = (data: any) => {

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never" v-loading="loading">

View File

@ -71,7 +71,7 @@ const formData = reactive({
is_auto_transfer: '0',
is_auto_verify: '0',
is_open: '0',
min: '0.01',
min: '0',
rate: '0',
transfer_type: []
})

View File

@ -2,7 +2,7 @@
<div class="main-container" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
@ -97,6 +97,10 @@ import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/tools/addon')
}
const form = ref({
title: '',
icon: '',

View File

@ -2,7 +2,7 @@
<div class="main-container" v-loading="loading">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :icon="ArrowLeft" @back="$router.back()">
<el-page-header :icon="ArrowLeft" @back="back()">
<template #content>
<span class="text-large font-600 mr-3">{{ pageName }}</span>
</template>
@ -122,7 +122,11 @@ import { ElMessageBox, ElMessage, FormInstance } from 'element-plus'
import { useRouter, useRoute } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const back = () => {
router.push('/tools/schedule')
}
const cronTableData = reactive({
page: 1,

View File

@ -0,0 +1,170 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[15px] ml-[15px]">
<div class="flex items-center">
<div class="text-[#666] cursor-pointer text-[14px]" @click="router.push(`/web/adv_position`)">
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
<span class="ml-[1px]">{{ t('returnToPreviousPage') }}</span>
</div>
<span class="text-[#999] mx-[12px]">|</span>
<span class="right">{{ pageName }}</span>
</div>
<el-button type="primary" @click="addEvent">{{ t('addAdv') }}</el-button>
</div>
<div class="mt-[10px]">
<el-table :data="advTable.data" size="large" v-loading="advTable.loading">
<template #empty>
<span>{{ !advTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="adv_title" :label="t('advName')" min-width="120" />
<el-table-column :label="t('advUrl')" min-width="120">
<template #default="{ row }">
<div>{{ row.adv_url ? row.adv_url.url : '' }}</div>
</template>
</el-table-column>
<el-table-column prop="ap_name" :label="t('advPosition')" min-width="120" />
<el-table-column :label="t('advImg')" min-width="180">
<template #default="{ row }">
<div class="w-[40px] h-[40px] flex items-center">
<el-image :src="img(row.adv_image)" :zoom-rate="1.2" :max-scale="7" :min-scale="0.2" :preview-src-list="[img(row.adv_image)]" :initial-index="4" fit="cover" />
</div>
</template>
</el-table-column>
<el-table-column :label="t('sort')" min-width="120">
<template #default="{ row }">
<el-input v-model.trim="row.sort" class="!w-[70px]" maxlength="8" @blur="sortInputListener(row.sort, row)" />
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" min-width="120" align="right">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.adv_id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="advTable.page" v-model:page-size="advTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="advTable.total"
@size-change="loadAdvList()" @current-change="loadAdvList" />
</div>
</div>
<edit ref="editAdvDialog" @complete="loadAdvList" />
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { getAdvList, deleteAdv, editAdvSort } from '@/app/api/web'
import { img, debounce } from '@/utils/common'
import { ElMessageBox, ElMessage } from 'element-plus'
import Edit from '@/app/views/web/components/adv-edit.vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const advKey = route.query.adv_key
const apName = route.query.ap_name
const advTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: []
})
/**
* 获取广告列表
*/
const loadAdvList = (page: number = 1) => {
advTable.loading = true
advTable.page = page
getAdvList({
page: advTable.page,
limit: advTable.limit,
adv_key: advKey
}).then(res => {
advTable.loading = false
advTable.data = res.data.data
advTable.total = res.data.total
}).catch(() => {
advTable.loading = false
})
}
loadAdvList()
const editAdvDialog: Record<string, any> | null = ref(null)
/**
* 添加广告
*/
const addEvent = () => {
editAdvDialog.value.setFormData({adv_key: advKey, ap_name: apName})
editAdvDialog.value.showDialog = true
}
/**
* 编辑广告
* @param data
*/
const editEvent = (data: any) => {
editAdvDialog.value.setFormData(data)
editAdvDialog.value.showDialog = true
}
/**
* 删除广告
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('advDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
deleteAdv(id).then(() => {
loadAdvList()
}).catch(() => {
})
})
}
//
const regExp = {
number: /^\d{0,10}$/,
digit: /^\d{0,10}(.?\d{0,2})$/
}
//
const sortInputListener = debounce((sort, row) => {
if (isNaN(sort) || !regExp.number.test(sort)) {
ElMessage({
type: 'warning',
message: `${t('sortTips')}`
})
return
}
if (sort > 99999999) {
row.sort = 99999999
}
editAdvSort({
id: row.adv_id,
sort
}).then((res: any) => {
loadAdvList()
})
})
</script>
<style lang="scss" scoped>
.input-width-sort {
width: 70px;
}
</style>

View File

@ -0,0 +1,55 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-table :data="avdPositionTableData.data" size="large" v-loading="avdPositionTableData.loading">
<template #empty>
<span>{{ !avdPositionTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="ap_name" :label="t('apName')" min-width="120" />
<el-table-column prop="keywords" :label="t('keywords')" min-width="120" />
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
<template #default="{ row }">
<el-button type="primary" link @click="toLink(row)">{{ t('manageAdv') }}</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { t } from '@/lang'
import { getAvdPositionList } from '@/app/api/web'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const pageName = route.meta.title
const avdPositionTableData: any = reactive({
loading: true,
data: []
})
// 广
const loadAvdPositionList = () => {
getAvdPositionList({}).then(res => {
avdPositionTableData.loading = false
avdPositionTableData.data = res.data
}).catch(() => {
avdPositionTableData.loading = false
})
}
loadAvdPositionList()
const toLink = (data: any) => {
router.push(`/web/adv?adv_key=${data.keywords}&ap_name=${data.ap_name}`)
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,146 @@
<template>
<el-dialog v-model="showDialog" :title="formData.adv_id ? t('updateAdv') : t('addAdv')" width="30%" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('advName')" prop="adv_title">
<el-input v-model.trim="formData.adv_title" clearable :placeholder="t('advNamePlaceholder')" class="input-width" maxlength="20" />
</el-form-item>
<el-form-item :label="t('advPosition')" prop="ap_name">
<el-input v-model.trim="formData.ap_name" disabled class="input-width" />
</el-form-item>
<el-form-item :label="t('advUrl')">
<web-link v-model="formData.adv_url" />
</el-form-item>
<el-form-item :label="t('advImg')" prop="adv_image">
<upload-image v-model="formData.adv_image" />
</el-form-item>
<el-form-item :label="t('background')">
<el-color-picker v-model="formData.background" />
</el-form-item>
<el-form-item :label="t('sort')" prop="sort">
<el-input v-model.trim="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" show-word-limit maxlength="8" @keyup="filterNumber($event)" @blur="formData.sort = $event.target.value" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addAdv, editAdv, getAdvInfo } from '@/app/api/web'
const showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
adv_key: '',
ap_name: '',
adv_id: '',
adv_title: '',
adv_url: {
name : ''
},
adv_image: '',
sort: '',
background: ''
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const regExp: any = {
number: /^\d{0,10}$/
}
//
const formRules = computed(() => {
return {
adv_title: [
{ required: true, message: t('advNamePlaceholder'), trigger: 'blur' }
],
adv_image: [
{ required: true, message: t('advImagePlaceholder'), trigger: 'blur' }
],
sort: [
{
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (isNaN(value) || !regExp.number.test(value)) {
callback(new Error(t('sortTips')))
} else {
callback()
}
}
}
],
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
const save = formData.adv_id ? editAdv : addAdv
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(() => {
loading.value = false
})
}
})
}
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row.adv_id) {
const data = await (await getAdvInfo(row.adv_id)).data
if (data) {
Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
} else {
formData.adv_key = row.adv_key
formData.ap_name = row.ap_name
}
loading.value = false
}
//
const link: any = ref([])
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
</style>

View File

@ -0,0 +1,146 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateFriendlyLink') : t('addFriendlyLink')" width="500px" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('linkPic')">
<upload-image v-model="formData.link_pic" />
</el-form-item>
<el-form-item :label="t('linkTitle')" prop="link_title">
<el-input v-model="formData.link_title" clearable :placeholder="t('linkTitlePlaceholder')" class="input-width" maxlength="20" />
</el-form-item>
<el-form-item :label="t('linkUrl')" prop="link_url">
<el-input v-model="formData.link_url" clearable :placeholder="t('linkUrlPlaceholder')" class="input-width" />
</el-form-item>
<el-form-item :label="t('sort')" prop="sort">
<el-input v-model.trim="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" show-word-limit maxlength="8" @keyup="filterNumber($event)" @blur="formData.sort = $event.target.value" />
</el-form-item>
<el-form-item :label="t('isShow')">
<el-switch v-model="formData.is_show" :active-value="1" :inactive-value="0" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addFriendlyLink, editFriendlyLink, getFriendlyLinkInfo } from '@/app/api/web'
const showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
link_pic: '',
link_title: '',
link_url: '',
sort: '',
is_show: 1
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const regExp: any = {
number: /^\d{0,10}$/,
}
//
const formRules = computed(() => {
return {
link_pic: [
{ required: true, message: t('linkPicPlaceholder'), trigger: 'blur' }
],
link_title: [
{ required: true, message: t('linkTitlePlaceholder'), trigger: 'blur' }
],
link_url: [
{ required: true, message: t('linkUrlPlaceholder'), trigger: 'blur' },
{
validator: (rule: any, value: string, callback: any) => {
const pattern = /^(http|https):\/\/.+/
if (value && !pattern.test(value)) {
callback(new Error(t('addressTips')))
} else { callback() }
}
}
],
sort: [
{
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (isNaN(value) || !regExp.number.test(value)) {
callback(new Error(t('sortTips')))
} else {
callback()
}
}
}
],
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
const save = formData.id ? editFriendlyLink : addFriendlyLink
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(() => {
loading.value = false
})
}
})
}
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
const data = await (await getFriendlyLinkInfo(row.id)).data
if (data) {
Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
}
loading.value = false
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
</style>

View File

@ -0,0 +1,151 @@
<template>
<el-dialog v-model="showDialog" :title="formData.id ? t('updateNav') : t('addNav')" width="500px" class="diy-dialog-wrap" :destroy-on-close="true">
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-form-item :label="t('navTitle')" prop="nav_title">
<el-input v-model.trim="formData.nav_title" clearable :placeholder="t('navTitlePlaceholder')" class="input-width" maxlength="20" />
</el-form-item>
<el-form-item :label="t('navUrl')" prop="nav_url">
<web-link v-model="formData.nav_url" />
</el-form-item>
<el-form-item :label="t('sort')" prop="sort">
<el-input v-model.trim="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" show-word-limit maxlength="8" @keyup="filterNumber($event)" @blur="formData.sort = $event.target.value" />
</el-form-item>
<el-form-item :label="t('isBlank')">
<el-switch v-model="formData.is_blank" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item :label="t('isShow')">
<el-switch v-model="formData.is_show" :active-value="1" :inactive-value="0" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { filterNumber } from '@/utils/common'
import { addNav, editNav, getNavInfo } from '@/app/api/web'
const showDialog = ref(false)
const loading = ref(false)
/**
* 表单数据
*/
const initialFormData = {
id: '',
nav_title: '',
nav_url: {
name : ''
},
sort: '',
is_blank: 1,
is_show: 1
}
const formData: Record<string, any> = reactive({ ...initialFormData })
const formRef = ref<FormInstance>()
//
const regExp: any = {
number: /^\d{0,10}$/,
}
//
const formRules = computed(() => {
return {
nav_title: [
{ required: true, message: t('navTitlePlaceholder'), trigger: 'blur' }
],
nav_url: [
{
required: true,
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (!value.url) {
callback(new Error(t('navUrlPlaceholder')))
} else {
callback()
}
}
}
],
is_blank: [
{ required: true, message: t('isBlankPlaceholder'), trigger: 'blur' }
],
sort: [
{
trigger: 'blur',
validator: (rule: any, value: any, callback: any) => {
if (isNaN(value) || !regExp.number.test(value)) {
callback(new Error(t('sortTips')))
} else {
callback()
}
}
}
],
}
})
const emit = defineEmits(['complete'])
/**
* 确认
* @param formEl
*/
const confirm = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
const save = formData.id ? editNav : addNav
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const data = formData
save(data).then(res => {
loading.value = false
showDialog.value = false
emit('complete')
}).catch(() => {
loading.value = false
})
}
})
}
const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData)
loading.value = true
if (row) {
const data = await (await getNavInfo(row.id)).data
if (data) {
Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key]
})
}
}
loading.value = false
}
defineExpose({
showDialog,
setFormData
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.diy-dialog-wrap .el-form-item__label {
height: auto !important;
}
</style>

View File

@ -0,0 +1,177 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<el-button type="primary" @click="addEvent">{{ t('addFriendlyLink') }}</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="friendlyLinkTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('linkTitle')" prop="link_title">
<el-input v-model="friendlyLinkTable.searchParam.link_title" :placeholder="t('linkTitlePlaceholder')" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadFriendlyLinkList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table :data="friendlyLinkTable.data" size="large" v-loading="friendlyLinkTable.loading">
<template #empty>
<span>{{ !friendlyLinkTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="link_title" :label="t('linkTitle')" min-width="120" />
<el-table-column prop="link_url" :label="t('linkUrl')" min-width="200" />
<el-table-column prop="sort" :label="t('sort')" min-width="120">
<template #default="{ row }">
<el-input v-model.trim="row.sort" class="!w-[70px]" maxlength="8" @blur="sortInputListener(row.sort, row)" />
</template>
</el-table-column>
<el-table-column :label="t('isShow')" min-width="180" align="center">
<template #default="{ row }">
{{ row.is_show == 1 ? t('show') : t('hidden') }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" min-width="120" align="right">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="friendlyLinkTable.page" v-model:page-size="friendlyLinkTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="friendlyLinkTable.total"
@size-change="loadFriendlyLinkList()" @current-change="loadFriendlyLinkList" />
</div>
</div>
<edit ref="editFriendlyLinkDialog" @complete="loadFriendlyLinkList" />
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { getFriendlyLinkList, deleteFriendlyLink, editFriendlyLinkSort } from '@/app/api/web'
import { debounce } from '@/utils/common'
import { ElMessageBox, ElMessage, FormInstance } from 'element-plus'
import Edit from '@/app/views/web/components/friendly-link-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const friendlyLinkTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
link_title: ''
}
})
const searchFormRef = ref<FormInstance>()
/**
* 获取友情链接列表
*/
const loadFriendlyLinkList = (page: number = 1) => {
friendlyLinkTable.loading = true
friendlyLinkTable.page = page
getFriendlyLinkList({
page: friendlyLinkTable.page,
limit: friendlyLinkTable.limit,
...friendlyLinkTable.searchParam
}).then(res => {
friendlyLinkTable.loading = false
friendlyLinkTable.data = res.data.data
friendlyLinkTable.total = res.data.total
}).catch(() => {
friendlyLinkTable.loading = false
})
}
loadFriendlyLinkList()
const editFriendlyLinkDialog: Record<string, any> | null = ref(null)
/**
* 添加友情链接
*/
const addEvent = () => {
editFriendlyLinkDialog.value.setFormData()
editFriendlyLinkDialog.value.showDialog = true
}
/**
* 编辑友情链接
* @param data
*/
const editEvent = (data: any) => {
editFriendlyLinkDialog.value.setFormData(data)
editFriendlyLinkDialog.value.showDialog = true
}
/**
* 删除友情链接
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('friendlyLinkDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
deleteFriendlyLink(id).then(() => {
loadFriendlyLinkList()
}).catch(() => {
})
})
}
//
const regExp = {
number: /^\d{0,10}$/,
digit: /^\d{0,10}(.?\d{0,2})$/
}
//
const sortInputListener = debounce((sort, row) => {
if (isNaN(sort) || !regExp.number.test(sort)) {
ElMessage({
type: 'warning',
message: `${t('sortTips')}`
})
return
}
if (sort > 99999999) {
row.sort = 99999999
}
editFriendlyLinkSort({
id: row.id,
sort
}).then((res: any) => {
loadFriendlyLinkList()
})
})
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadFriendlyLinkList()
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,190 @@
<template>
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-lg">{{ pageName }}</span>
<el-button type="primary" @click="addEvent">{{ t('addNav') }}</el-button>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="navTable.searchParam" ref="searchFormRef">
<el-form-item :label="t('navTitle')" prop="nav_title">
<el-input v-model="navTable.searchParam.nav_title" :placeholder="t('navTitlePlaceholder')" maxlength="20" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadNavList()">{{ t('search') }}</el-button>
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="mt-[10px]">
<el-table :data="navTable.data" size="large" v-loading="navTable.loading">
<template #empty>
<span>{{ !navTable.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="nav_title" :label="t('navTitle')" min-width="120" />
<el-table-column prop="nav_url" :label="t('navUrl')" min-width="120" >
<template #default="{ row }">
<div>{{ row.nav_url ? row.nav_url.url : '' }}</div>
</template>
</el-table-column>
<el-table-column prop="sort" :label="t('sort')" min-width="120">
<template #default="{ row }">
<el-input v-model.trim="row.sort" class="!w-[70px]" maxlength="8" @blur="sortInputListener(row.sort, row)" />
</template>
</el-table-column>
<el-table-column :label="t('isBlank')" min-width="180" align="center" >
<template #default="{ row }">
{{ row.is_blank == 1 ? t('yes') : t('no') }}
</template>
</el-table-column>
<el-table-column :label="t('createTime')" min-width="180" align="center">
<template #default="{ row }">
{{ row.create_time || '' }}
</template>
</el-table-column>
<el-table-column :label="t('isShow')" min-width="180" align="center">
<template #default="{ row }">
{{ row.is_show == 1 ? t('show') : t('hidden') }}
</template>
</el-table-column>
<el-table-column :label="t('operation')" fixed="right" min-width="120" align="right">
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="navTable.page" v-model:page-size="navTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="navTable.total"
@size-change="loadNavList()" @current-change="loadNavList" />
</div>
</div>
<edit ref="editNavDialog" @complete="loadNavList" />
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { debounce } from '@/utils/common'
import { getNavList, deleteNav, editNavSort } from '@/app/api/web'
import { ElMessageBox, FormInstance, ElMessage } from 'element-plus'
import Edit from '@/app/views/web/components/nav-edit.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const pageName = route.meta.title
const navTable = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
nav_title: ''
}
})
const searchFormRef = ref<FormInstance>(null)
/**
* 获取PC导航管理列表
*/
const loadNavList = (page: number = 1) => {
navTable.loading = true
navTable.page = page
getNavList({
page: navTable.page,
limit: navTable.limit,
...navTable.searchParam
}).then(res => {
navTable.loading = false
navTable.data = res.data.data
navTable.total = res.data.total
}).catch(() => {
navTable.loading = false
})
}
loadNavList()
const editNavDialog: Record<string, any> | null = ref(null)
/**
* 添加PC导航管理
*/
const addEvent = () => {
editNavDialog.value.setFormData()
editNavDialog.value.showDialog = true
}
/**
* 编辑PC导航管理
* @param data
*/
const editEvent = (data: any) => {
editNavDialog.value.setFormData(data)
editNavDialog.value.showDialog = true
}
/**
* 删除PC导航管理
*/
const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('navDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
deleteNav(id).then(() => {
loadNavList()
}).catch(() => {
})
})
}
//
const regExp = {
number: /^\d{0,10}$/,
digit: /^\d{0,10}(.?\d{0,2})$/
}
//
const sortInputListener = debounce((sort, row) => {
if (isNaN(sort) || !regExp.number.test(sort)) {
ElMessage({
type: 'warning',
message: `${t('sortTips')}`
})
return
}
if (sort > 99999999) {
row.sort = 99999999
}
editNavSort({
id: row.id,
sort
}).then((res: any) => {
loadNavList()
})
})
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return
formEl.resetFields()
loadNavList()
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,214 @@
<template>
<div>
<div @click="show">
<slot>
<el-input v-model="value.title" :placeholder="t('linkPlaceholder')" readonly class="link-input">
<template #suffix>
<div @click.stop="clear">
<el-icon v-if="value.name">
<Close />
</el-icon>
<el-icon v-else>
<ArrowRight />
</el-icon>
</div>
</template>
</el-input>
</slot>
</div>
<el-dialog v-model="showDialog" :title="t('selectLinkTips')" width="40%" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
<div class="flex items-start">
<el-scrollbar class="w-[140px] border-r h-[350px]">
<div v-for="(item, index) in link" :key="index"
class="h-[40px] leading-[40px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
:class="[item.name == parentLinkName ? 'bg-primary-light-9 text-primary' : '']"
@click="changeParentLink(item)">
{{ item.title }}
</div>
</el-scrollbar>
<el-scrollbar class="pl-4 h-[350px] flex-1">
<template v-if="parentLinkName == 'DIY_LINK'">
<div class="mb-[16px]">
<el-form-item :label="t('diyLinkName')">
<el-input v-model="selectLink.title" :placeholder="t('diyLinkNamePlaceholder')" class="w-6/12" />
</el-form-item>
</div>
<div class="mb-[16px]">
<el-form-item :label="t('diyLinkUrl')">
<el-input v-model="selectLink.url" :placeholder="t('diyLinkUrlPlaceholder')" class="w-6/12" />
</el-form-item>
</div>
<el-form-item label=" ">
<div class="text-sm text-gray-400 select-text">路径必须以/开头/index/index</div>
</el-form-item>
<el-form-item label=" ">
<div class="text-sm text-gray-400 select-text">跳转外部链接httphttps开头https://baidu.com</div>
</el-form-item>
</template>
<div v-else class="flex flex-wrap">
<div v-for="(item, index) in childList" :key="index"
class="border border-br rounded-[3px] mr-[10px] mb-[10px] px-4 h-[32px] leading-[32px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
:class="[item.name == selectLink.name ? 'border-primary text-primary' : '']"
@click="changeChildLink(item)">{{ item.title }}
</div>
</div>
</el-scrollbar>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref, computed } from 'vue'
import { cloneDeep } from 'lodash-es'
import { getLink } from '@/app/api/web'
import { ElMessage } from 'element-plus'
const prop = defineProps({
modelValue: {
type: Object,
default: () => {}
}
})
const emit = defineEmits(['update:modelValue'])
const value: any = computed({
get () {
return prop.modelValue
},
set (value) {
emit('update:modelValue', value)
}
})
const showDialog = ref(false)
//
const link: any = ref([])
const parentLinkName = ref('')
//
const childList: any = ref([])
//
const selectLink: any = ref({})
const show = () => {
getLinkFn(() => {
//
if (value.value.name != '') {
selectLink.value = cloneDeep(value.value)
parentLinkName.value = selectLink.value.parent
for (let key in link.value) {
if (link.value[key].name == parentLinkName.value) {
changeParentLink(link.value[key])
}
}
}
showDialog.value = true
})
}
const getLinkFn = (callback:any=null)=> {
getLink({}).then((res: any) => {
link.value = res.data
if (prop.ignore && prop.ignore.length) {
for (let key in link.value) {
for (let i = 0; i < prop.ignore.length; i++) {
if (key == prop.ignore[i]) {
delete link.value[key];
break;
}
}
}
}
childList.value = Object.values(link.value)[0].child_list
if (value.value.name != '') {
selectLink.value = cloneDeep(value.value)
} else {
selectLink.value = {
parent: Object.values(link.value)[0].name
}
}
parentLinkName.value = selectLink.value.parent
if (callback) callback()
})
}
//
const changeParentLink = (item: any) => {
childList.value = item.child_list
parentLinkName.value = item.name
}
//
const changeChildLink = (item: any) => {
delete item.is_share
selectLink.value = cloneDeep(item)
}
const clear = () => {
value.value = {
name: '',
parent: '',
title: '',
url: ''
}
}
const save = () => {
if (parentLinkName.value === 'DIY_LINK') {
//
if (!selectLink.value.title) {
ElMessage({
message: t('diyLinkNameNotEmpty'),
type: 'warning'
})
return
}
if (!selectLink.value.url) {
ElMessage({
message: t('diyLinkUrlNotEmpty'),
type: 'warning'
})
return
}
selectLink.value.parent = parentLinkName.value
selectLink.value.name = parentLinkName.value
selectLink.value.action = ''
} else if (parentLinkName.value == 'DIY_PAGE') {
//
selectLink.value.parent = parentLinkName.value
selectLink.value.action = 'decorate'
}
value.value = cloneDeep(selectLink.value)
showDialog.value = false
emit('success')
}
defineExpose({
showDialog
})
</script>
<style lang="scss">
.link-input .el-input__inner {
cursor: pointer;
}
</style>

View File

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3883393 */
src: url('//at.alicdn.com/t/c/font_3883393_t4cbwq5qdz.woff2?t=1729077942624') format('woff2'),
url('//at.alicdn.com/t/c/font_3883393_t4cbwq5qdz.woff?t=1729077942624') format('woff'),
url('//at.alicdn.com/t/c/font_3883393_t4cbwq5qdz.ttf?t=1729077942624') format('truetype');
src: url('//at.alicdn.com/t/c/font_3883393_xso0134odj.woff2?t=1732777083024') format('woff2'),
url('//at.alicdn.com/t/c/font_3883393_xso0134odj.woff?t=1732777083024') format('woff'),
url('//at.alicdn.com/t/c/font_3883393_xso0134odj.ttf?t=1732777083024') format('truetype');
}
.iconfont {
@ -13,6 +13,18 @@
-moz-osx-font-smoothing: grayscale;
}
.iconshujutongji:before {
content: "\e835";
}
.iconshangpinguanli1:before {
content: "\e837";
}
.icondingdanguanli:before {
content: "\e838";
}
.icona-tupianzhanbopc302:before {
content: "\e83c";
}

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ export function setThemeColor(color: string, mode: string = 'light'): void {
}
Object.keys(colors[mode]).forEach((key) => {
useCssVar('--el-color-primary' + '-' + key, null).value = colorFunction.convert(`color(${color} ${colors[mode][key]})`)
useCssVar('--el-color-primary' + '-' + key, null).value = colorFunction.convert(`color(${ color } ${ colors[mode][key] })`)
})
}
@ -48,7 +48,9 @@ export function setThemeColor(color: string, mode: string = 'light'): void {
* 访
*/
export function getAppType() {
const path = location.pathname.split('/').filter((val) => { return val })
const path = location.pathname.split('/').filter((val) => {
return val
})
if (!path.length) {
return 'admin'
@ -125,7 +127,7 @@ export function isUrl(str: string): boolean {
* @returns
*/
export function img(path: string): string {
return isUrl(path) ? path : `${import.meta.env.VITE_IMG_DOMAIN || location.origin}/${path}`
return isUrl(path) ? path : `${ import.meta.env.VITE_IMG_DOMAIN || location.origin }/${ path }`
}
/**
@ -133,7 +135,7 @@ export function img(path: string): string {
* @param path
* @returns
*/
export function assetImg (path: string) {
export function assetImg(path: string) {
return new URL('@/', import.meta.url) + path
}
@ -228,16 +230,16 @@ export function guid(len = 10, firstU = true, radix: any = null) {
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
if (firstU) {
uuid.shift()
return `u${uuid.join('')}`
return `u${ uuid.join('') }`
}
return uuid.join('')
}
/**
*
*/
export function moneyFormat(money : string) : string {
return isNaN(parseFloat(money)) ? money : parseFloat(money).toFixed(2)
*
*/
export function moneyFormat(money: string): string {
return isNaN(parseFloat(money)) ? money : parseFloat(money).toFixed(2)
}
@ -245,63 +247,151 @@ export function moneyFormat(money : string) : string {
*
*/
export function timeStampTurnTime(timeStamp: any, type = "") {
if (timeStamp != undefined && timeStamp != "" && timeStamp > 0) {
var date = new Date();
date.setTime(timeStamp * 1000);
var y: any = date.getFullYear();
var m: any = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d: any = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h: any = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute: any = date.getMinutes();
var second: any = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if (type) {
if (type == 'yearMonthDay') {
return y + '年' + m + '月' + d + '日';
}
return y + '-' + m + '-' + d;
} else {
return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
}
if (timeStamp != undefined && timeStamp != "" && timeStamp > 0) {
var date = new Date();
date.setTime(timeStamp * 1000);
var y: any = date.getFullYear();
var m: any = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d: any = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h: any = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute: any = date.getMinutes();
var second: any = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if (type) {
if (type == 'yearMonthDay') {
return y + '年' + m + '月' + d + '日';
}
return y + '-' + m + '-' + d;
} else {
return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
}
} else {
return "";
}
} else {
return "";
}
}
/**
* ()
* @param event
*/
export function filterDigit(event:any){
event.target.value = event.target.value.replace(/[^\d\.]/g,'');
event.target.value = event.target.value.replace(/^\./g,'');
event.target.value = event.target.value.replace(/\.{2,}/g,'.');
export function filterDigit(event: any) {
event.target.value = event.target.value.replace(/[^\d\.]/g, '');
event.target.value = event.target.value.replace(/^\./g, '');
event.target.value = event.target.value.replace(/\.{2,}/g, '.');
// 限制最多两位小数
const decimalParts = event.target.value.split('.');
if (decimalParts.length > 1 && decimalParts[1].length > 2) {
// 如果有小数部分且超过两位,则截取前两位
event.target.value = `${decimalParts[0]}.${decimalParts[1].slice(0, 2)}`;
event.target.value = `${ decimalParts[0] }.${ decimalParts[1].slice(0, 2) }`;
}
}
/**
*
* @param event
* @param event
*/
export function filterNumber(event:any){
event.target.value = event.target.value.replace(/[^\d]/g,'');
export function filterNumber(event: any) {
event.target.value = event.target.value.replace(/[^\d]/g, '');
}
/**
*
* @param event
* @param event
*/
export function filterSpecial(event:any){
export function filterSpecial(event: any) {
event.target.value = event.target.value.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '')
event.target.value = event.target.value.replace(/[`~!@#$%^&*()_\-+=<>?:"{}|,.\/;'\\[\]·~@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g,'')
}
event.target.value = event.target.value.replace(/[`~!@#$%^&*()_\-+=<>?:"{}|,.\/;'\\[\]·~@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g, '')
}
export function importIconFontCss() {
// const modulesFiles = {}; // import.meta.glob('@/styles/icon/official-iconfont.css', { eager: true })
// const modulesFiles = import.meta.glob('@/addon/**/assets/icon/*.css', { eager: true })
// // console.log('modulesFiles',modulesFiles)
//
// const modules:any = {}
// for (const [key, value] of Object.entries(modulesFiles)) {
// const moduleName:any = key.split('/').pop()
// const name = moduleName.split('.')[0]
// modules[name] = value.default
// }
//
// // console.log('modules',modules)
//
// for(let key in modules) {
// // console.log('modules[key]',modules[key])
// import(modules[key]).then((module) => {
// // console.log('module', module.default);
// }).catch((e) => {
// // console.log('caca', e)
// });
// }
}
export function getIcon() {
// const modulesFiles = import.meta.glob('@/styles/icon/*.json', { eager: true })
// const addonModulesFiles = import.meta.glob('@/addon/**/assets/icon/*.json', { eager: true })
// addonModulesFiles && Object.assign(modulesFiles, addonModulesFiles)
//
// // const modulesFiles = {}; // import.meta.glob('@/styles/icon/official-iconfont.css', { eager: true })
// // const modulesFiles = import.meta.glob('@/styles/icon/*.json', { eager: true })
// console.log('modulesFiles', modulesFiles)
//
// const modules = {}
// for (const [key, value] of Object.entries(modulesFiles)) {
// const moduleName = key.split('/').pop()
// console.log('moduleName',moduleName)
// const name = moduleName.split('.')[0]
// modules[name] = value.default
// }
// console.log('modules', modules)
// // const addonModulesFiles = import.meta.glob('@/addon/**/assets/icon/*.json', { eager: true })
}
/**
*
* @param page
* @param limit
* @param where
*/
export function setTablePageStorage(page: any = 1, limit: any = 10, where: any = {}) {
var data = storage.get('tablePageStorage');
if (!data) {
data = {};
}
var key = location.pathname + JSON.stringify(where);
data[key] = {
page,
limit
};
var MAX_COUNT = 5; // 最多存储 5 个页面的分页缓存,超出则删除最开始的第一个页面
if (Object.keys(data).length > MAX_COUNT) {
delete data[Object.keys(data)[0]];
}
storage.set({ key: 'tablePageStorage', data });
}
/**
*
* @param where
*/
export function getTablePageStorage(where: any = {}) {
var data = storage.get('tablePageStorage');
var key = location.pathname + JSON.stringify(where);
if (!data || !data[key]) {
data = {
page: 1,
limit: 10
};
} else {
data = data[key];
}
return data;
}