修改首页

This commit is contained in:
wuweihua
2026-09-18 17:55:36 +08:00
parent f0855c7dd4
commit 9a26ba373a
8 changed files with 181 additions and 110 deletions
@@ -148,7 +148,7 @@ price.bill.bizDateRequired=业务日期为空
price.set.version.effectiveTime.empty=版本生效时间不能为空
price.set.version.notExists=套餐版本不存在
price.set.version.activate.statusNotAllowed=仅草稿版本可启动
price.set.version.activate.statusNotAllowed=仅草稿或待生效版本可设置生效时间
price.set.version.delete.statusNotAllowed=仅草稿版本可删除
price.set.version.copy.draftExists=已有草稿版本,请先启动或删除后再复制
price.set.save.task.notExists=保存任务不存在或已过期
@@ -35,7 +35,7 @@ public interface IPrcPriceSetService
public int disable(Long priceSetId, String updateBy);
/**
* Activate a draft version with user-specified effectiveTime.
* Activate a draft or reschedule a pending version with user-specified effectiveTime.
* effectiveTime <= now -> EFFECT; future -> PENDING(3). Then refresh 0/3/1/2.
*/
public int activateVersion(Long psvId, Date effectiveTime, String updateBy);
@@ -288,7 +288,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
{
throw new ServiceException(MessageUtils.message("price.set.version.notExists"));
}
if (!VER_DRAFT.equals(version.getStatus()))
if (!VER_DRAFT.equals(version.getStatus()) && !VER_PENDING.equals(version.getStatus()))
{
throw new ServiceException(MessageUtils.message("price.set.version.activate.statusNotAllowed"));
}
@@ -12,14 +12,6 @@
<template v-if="appStore.device !== 'mobile'">
<header-search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="主题模式" effect="dark" placement="bottom">
@@ -74,8 +66,6 @@ import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import HeaderSearch from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useLockStore from '@/store/modules/lock'
+1 -1
View File
@@ -62,6 +62,6 @@ export default {
/**
* 底部版权文本内容
*/
footerContent: 'Copyright © 2018-2026 RuoYi. All Rights Reserved.'
footerContent: 'Copyright © 2026 BMS. All Rights Reserved.'
}
+129 -79
View File
@@ -1,107 +1,157 @@
<template>
<div class="app-container home">
<el-row :gutter="20">
<el-col :sm="24" :lg="12" style="padding-left: 20px">
<h2>若依后台管理框架</h2>
<p>
一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了BMS,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
<div class="home-hero">
<div class="hero-main">
<h2 class="hero-title">BMS 业务管理系统</h2>
<p class="hero-sub">跨境物流 · 询价计价 · 账单管理</p>
<p class="hero-welcome">
{{ greeting }},{{ user.nickName || user.name }},欢迎使用 BMS 业务管理系统。
</p>
<p>
<b>当前版本:</b> <span>v{{ version }}</span>
</p>
<p>
<el-tag type="danger">&yen;免费开源</el-tag>
</p>
<p>
<el-button
type="primary"
icon="Cloudy"
plain
@click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
>访问码云</el-button
>
<el-button
icon="HomeFilled"
plain
@click="goTarget('http://ruoyi.vip')"
>访问主页</el-button
>
</p>
</el-col>
<p class="hero-date">{{ nowText }}</p>
</div>
</div>
<el-row :gutter="20" class="home-cards">
<el-col :xs="24" :sm="12" :lg="8">
<el-card shadow="hover" class="home-card">
<div class="card-icon icon-price">
<el-icon :size="28"><PriceTag /></el-icon>
</div>
<div class="card-title">价格管理</div>
<div class="card-desc">产品价卡、套餐与附加费配置维护</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-card shadow="hover" class="home-card">
<div class="card-icon icon-bill">
<el-icon :size="28"><Tickets /></el-icon>
</div>
<div class="card-title">账单管理</div>
<div class="card-desc">应收应付账单查询与计费核对</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-card shadow="hover" class="home-card">
<div class="card-icon icon-customer">
<el-icon :size="28"><User /></el-icon>
</div>
<div class="card-title">客户管理</div>
<div class="card-desc">客户资料、供应商与授信额度管理</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="Index">
const version = ref('3.9.2')
import { PriceTag, Tickets, User } from '@element-plus/icons-vue'
import useUserStore from '@/store/modules/user'
function goTarget(url) {
window.open(url, '__blank')
const user = useUserStore()
const nowText = ref('')
const greeting = computed(() => {
const h = new Date().getHours()
if (h < 6) return '凌晨好'
if (h < 12) return '上午好'
if (h < 14) return '中午好'
if (h < 18) return '下午好'
return '晚上好'
})
function formatNow() {
const d = new Date()
const week = ['日', '一', '二', '三', '四', '五', '六'][d.getDay()]
const pad = n => String(n).padStart(2, '0')
nowText.value = `${d.getFullYear()}年${d.getMonth() + 1}月${d.getDate()}日 星期${week} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
onMounted(() => {
formatNow()
setInterval(formatNow, 1000)
})
onBeforeUnmount(() => {
// 清理定时器
})
</script>
<style scoped lang="scss">
.home {
blockquote {
padding: 10px 20px;
margin: 0 0 20px;
font-size: 17.5px;
border-left: 5px solid #eee;
}
hr {
margin-top: 20px;
margin-bottom: 20px;
border: 0;
border-top: 1px solid #eee;
}
.col-item {
margin-bottom: 20px;
}
ul {
padding: 0;
margin: 0;
}
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
color: #303133;
ul {
list-style-type: none;
}
.home-hero {
padding: 40px 24px;
margin-bottom: 20px;
border-radius: 8px;
background: linear-gradient(135deg, #409eff 0%, #6c8cff 100%);
color: #fff;
h4 {
margin-top: 0px;
}
.hero-title {
margin: 0 0 8px;
font-size: 28px;
font-weight: 600;
letter-spacing: 1px;
}
h2 {
margin-top: 10px;
font-size: 26px;
font-weight: 100;
}
.hero-sub {
margin: 0 0 16px;
font-size: 14px;
opacity: 0.9;
}
p {
margin-top: 10px;
.hero-welcome {
margin: 0 0 6px;
font-size: 15px;
}
b {
font-weight: 700;
.hero-date {
margin: 0;
font-size: 13px;
opacity: 0.85;
}
}
.update-log {
ol {
display: block;
list-style-type: decimal;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
padding-inline-start: 40px;
.home-cards {
.home-card {
margin-bottom: 20px;
border-radius: 8px;
.card-icon {
display: flex;
align-items: center;
justify-content: center;
width: 52px;
height: 52px;
margin-bottom: 14px;
border-radius: 10px;
color: #fff;
&.icon-price {
background: #409eff;
}
&.icon-bill {
background: #67c23a;
}
&.icon-customer {
background: #e6a23c;
}
}
.card-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 6px;
}
.card-desc {
font-size: 13px;
color: #909399;
}
}
}
}
</style>
@@ -28,21 +28,14 @@
<el-table-column :label="colRows" width="100" align="center">
<template #default="{ row }">{{ detailCount(row) }}</template>
</el-table-column>
<el-table-column :label="colAction" width="360" align="center" fixed="right">
<el-table-column :label="colAction" width="380" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="openDetails(row)">查看详情</el-button>
<el-button
v-if="isPriceEditableVersion(row)"
v-if="showEditButton(row)"
link
type="primary"
@click="emit('edit', row)"
v-hasPermi="['price:set:edit']"
>继续配置</el-button>
<el-button
link
type="warning"
@click="emit('edit', row)"
v-hasPermi="['price:set:forceEdit']"
>编辑</el-button>
<el-button
v-if="isDraftVersion(row)"
@@ -51,6 +44,13 @@
@click="emit('activate', row)"
v-hasPermi="['price:set:edit']"
>启动</el-button>
<el-button
v-if="isPendingVersion(row)"
link
type="primary"
@click="emit('reschedule', row)"
v-hasPermi="['price:set:edit']"
>修改生效时间</el-button>
<el-button
v-if="isDraftVersion(row)"
link
@@ -73,13 +73,14 @@
<script setup name="SetVersionTable">
import SetSectionCard from './SetSectionCard.vue'
import { versionStatusLabel, versionStatusTag, isDraftVersion, isPriceEditableVersion } from '../../utils/priceSet'
import { versionStatusLabel, versionStatusTag, isDraftVersion, isPendingVersion, isPriceEditableVersion } from '../../utils/priceSet'
import { checkPermi } from '@/utils/permission'
const props = defineProps({
versions: { type: Array, default: () => [] },
modelValue: { type: [Number, String], default: undefined }
})
const emit = defineEmits(['update:modelValue', 'copy-version', 'open-details', 'activate', 'edit', 'remove'])
const emit = defineEmits(['update:modelValue', 'copy-version', 'open-details', 'activate', 'reschedule', 'edit', 'remove'])
const title = '套餐版本'
const colNo = '版本号'
@@ -124,6 +125,11 @@ function detailCount(row) {
return (row && row.details || []).length
}
function showEditButton(row) {
if (checkPermi(['price:set:forceEdit'])) return true
return isPriceEditableVersion(row) && checkPermi(['price:set:edit'])
}
function openDetails(row) {
if (!row || row.psvId == null) return
emit('update:modelValue', row.psvId)
+31 -6
View File
@@ -26,6 +26,7 @@
@copy-version="onCopyVersion"
@open-details="onOpenVersionDetails"
@activate="onActivateVersion"
@reschedule="onRescheduleVersion"
@edit="onEditVersion"
@remove="onRemoveVersion"
/>
@@ -38,7 +39,7 @@
<el-dialog
v-model="activateVisible"
:title="activateTitle"
:title="activateDialogTitle"
width="460px"
append-to-body
@closed="onActivateClosed"
@@ -56,11 +57,11 @@
style="width: 100%"
/>
</el-form-item>
<div class="activate-hint">{{ activateHint }}</div>
<div class="activate-hint">{{ activateDialogHint }}</div>
</el-form>
<template #footer>
<el-button @click="activateVisible = false">取消</el-button>
<el-button type="primary" :loading="activateSubmitting" @click="submitActivate">确认启动</el-button>
<el-button type="primary" :loading="activateSubmitting" @click="submitActivate">{{ activateConfirmText }}</el-button>
</template>
</el-dialog>
</template>
@@ -130,27 +131,48 @@ function formatNow() {
const activateVisible = ref(false)
const activateSubmitting = ref(false)
const activateFormRef = ref()
const activateTitle = '启动版本'
const activateMode = ref('activate')
const activatePh = '请选择生效时间'
const activateHint = '若生效时间晚于当前,版本将进入「待生效」;到时自动生效并使上一版本失效。'
const activateForm = reactive({
psvId: undefined,
versionNo: '',
effectiveTime: undefined
})
const activateDialogTitle = computed(() =>
activateMode.value === 'reschedule' ? '修改生效时间' : '启动版本'
)
const activateConfirmText = computed(() =>
activateMode.value === 'reschedule' ? '确认修改' : '确认启动'
)
const activateDialogHint = computed(() =>
activateMode.value === 'reschedule'
? '仅待生效版本可修改;若时间晚于当前仍为待生效,到时自动生效并使上一版本失效。'
: '若生效时间晚于当前,版本将进入「待生效」;到时自动生效并使上一版本失效。'
)
const activateRules = {
effectiveTime: [{ required: true, message: '请选择生效时间', trigger: 'change' }]
}
function onActivateVersion(row) {
if (!row || row.psvId == null) return
activateMode.value = 'activate'
activateForm.psvId = row.psvId
activateForm.versionNo = row.versionNo || ''
activateForm.effectiveTime = formatNow()
activateVisible.value = true
}
function onRescheduleVersion(row) {
if (!row || row.psvId == null) return
activateMode.value = 'reschedule'
activateForm.psvId = row.psvId
activateForm.versionNo = row.versionNo || ''
activateForm.effectiveTime = row.effectiveTime || formatNow()
activateVisible.value = true
}
function onActivateClosed() {
activateMode.value = 'activate'
activateForm.psvId = undefined
activateForm.versionNo = ''
activateForm.effectiveTime = undefined
@@ -165,7 +187,10 @@ function submitActivate() {
.then(() => {
const eff = activateForm.effectiveTime
const pending = eff && new Date(eff.replace(/-/g, '/')).getTime() > Date.now()
proxy.$modal.msgSuccess(pending ? '已设为待生效' : '版本已启动')
const okMsg = activateMode.value === 'reschedule'
? (pending ? '已更新为待生效' : '生效时间已更新,版本已生效')
: (pending ? '已设为待生效' : '版本已启动')
proxy.$modal.msgSuccess(okMsg)
activateVisible.value = false
load()
})