1
@@ -0,0 +1,8 @@
|
||||
ALTER TABLE `asset`
|
||||
MODIFY COLUMN `assetUnitPrice` DECIMAL(18, 2) NULL COMMENT '单价';
|
||||
|
||||
ALTER TABLE `asset_depreciation_record`
|
||||
MODIFY COLUMN `assetAllMoney` DECIMAL(18, 2) NULL COMMENT '资产全部的价值',
|
||||
MODIFY COLUMN `assetSurplusMoney` DECIMAL(18, 2) NULL COMMENT '剩余价值',
|
||||
MODIFY COLUMN `assetDepreciationMoney` DECIMAL(18, 2) NULL COMMENT '累计折旧多少钱',
|
||||
MODIFY COLUMN `assetAverageMonthMoney` DECIMAL(18, 2) NULL COMMENT '平均一个月多少钱';
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `build_home_little_house`
|
||||
ADD COLUMN `mapX` DECIMAL(8,4) NULL COMMENT '地图X坐标百分比' AFTER `mediaFiles`,
|
||||
ADD COLUMN `mapY` DECIMAL(8,4) NULL COMMENT '地图Y坐标百分比' AFTER `mapX`;
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `build_home_little_house`
|
||||
ADD COLUMN `unitId` VARCHAR(32) NULL COMMENT '单位ID' AFTER `unitName`,
|
||||
ADD COLUMN `mediaFiles` JSON NULL COMMENT '图片视频资料' AFTER `openTime`;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `honor`
|
||||
ADD COLUMN `photoFiles` JSON NULL COMMENT '荣誉照片' AFTER `files`;
|
||||
@@ -0,0 +1,64 @@
|
||||
-- Home work template menu. Prefer a sibling of sys.homeActivity, then sys.manager, then sys.
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
|
||||
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt,
|
||||
delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'e6ed122326a8492fa7f415f97eaf4f01',
|
||||
parent.id,
|
||||
CONCAT(parent.path, LPAD(IFNULL(child.maxNo, 0) + 1, 4, '0')),
|
||||
'Work Template',
|
||||
'Work Template',
|
||||
'menu',
|
||||
'/platform/sys/worktemplate',
|
||||
'data-pjax',
|
||||
'',
|
||||
1,
|
||||
0,
|
||||
'sys.worktemplate',
|
||||
NULL,
|
||||
IFNULL(child.maxLocation, 0) + 1,
|
||||
0,
|
||||
'',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000,
|
||||
'',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000,
|
||||
0,
|
||||
'PC',
|
||||
NULL,
|
||||
NULL,
|
||||
'g',
|
||||
0,
|
||||
0
|
||||
FROM (
|
||||
SELECT p.*
|
||||
FROM sys_menu p
|
||||
WHERE p.id = (SELECT h.parentId FROM sys_menu h WHERE h.permission = 'sys.homeActivity' LIMIT 1)
|
||||
OR p.permission IN ('sys.manager', 'sys')
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN p.id = (SELECT h.parentId FROM sys_menu h WHERE h.permission = 'sys.homeActivity' LIMIT 1) THEN 0
|
||||
WHEN p.permission = 'sys.manager' THEN 1
|
||||
ELSE 2
|
||||
END
|
||||
LIMIT 1
|
||||
) parent
|
||||
LEFT JOIN (
|
||||
SELECT parentId,
|
||||
MAX(CAST(RIGHT(path, 4) AS UNSIGNED)) AS maxNo,
|
||||
MAX(location) AS maxLocation
|
||||
FROM sys_menu
|
||||
GROUP BY parentId
|
||||
) child ON child.parentId = parent.id
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM sys_menu WHERE permission = 'sys.worktemplate'
|
||||
);
|
||||
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m ON m.permission = 'sys.worktemplate'
|
||||
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
|
||||
WHERE r.code = 'SYSADMIN'
|
||||
AND rm.roleId IS NULL;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `sys_config`
|
||||
MODIFY COLUMN `configValue` TEXT;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `sys_home_template`
|
||||
ADD COLUMN `templateIcon` varchar(255) DEFAULT NULL COMMENT 'template icon' AFTER `templateName`;
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `sys_home_template`
|
||||
ADD COLUMN `templateName` varchar(50) DEFAULT NULL COMMENT 'display template name' AFTER `name`;
|
||||
|
||||
UPDATE `sys_home_template`
|
||||
SET `templateName` = `name`
|
||||
WHERE (`templateName` IS NULL OR `templateName` = '');
|
||||
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE IF NOT EXISTS `sys_home_template` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'business id',
|
||||
`name` varchar(50) DEFAULT NULL COMMENT 'template name',
|
||||
`templateName` varchar(50) DEFAULT NULL COMMENT 'display template name',
|
||||
`templateIcon` varchar(255) DEFAULT NULL COMMENT 'template icon',
|
||||
`cover` varchar(255) DEFAULT NULL COMMENT 'template cover',
|
||||
`content` text COMMENT 'template content',
|
||||
`url` varchar(1000) DEFAULT NULL COMMENT 'pc url',
|
||||
`h5Url` varchar(1000) DEFAULT NULL COMMENT 'h5 url',
|
||||
`allowUserGroupId` int DEFAULT NULL COMMENT 'allowed user group id',
|
||||
`allowUserSql` varchar(1000) DEFAULT NULL COMMENT 'allowed user sql',
|
||||
`enable` tinyint(1) DEFAULT 0 COMMENT 'enabled',
|
||||
`classPath` varchar(500) DEFAULT NULL COMMENT 'source class path',
|
||||
`top` tinyint(1) DEFAULT 0 COMMENT 'top flag',
|
||||
`push` tinyint(1) DEFAULT 0 COMMENT 'push flag',
|
||||
`sortNo` int DEFAULT 0 COMMENT 'sort number',
|
||||
`startDate` datetime DEFAULT NULL COMMENT 'start date',
|
||||
`endDate` datetime DEFAULT NULL COMMENT 'end date',
|
||||
`createdBy` varchar(32) DEFAULT NULL,
|
||||
`createdAt` bigint DEFAULT NULL,
|
||||
`updatedBy` varchar(32) DEFAULT NULL,
|
||||
`updatedAt` bigint DEFAULT NULL,
|
||||
`delFlag` tinyint(1) DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='home work template';
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 557 KiB |
|
After Width: | Height: | Size: 557 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 994 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -18,6 +18,7 @@
|
||||
recognition: null,
|
||||
listening: false,
|
||||
menus: null,
|
||||
platform: "PC",
|
||||
parentMap: {},
|
||||
lastText: "",
|
||||
pendingMatches: [],
|
||||
@@ -128,7 +129,39 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getMenus() {
|
||||
function getCurrentPlatform() {
|
||||
const $button = $("#voice-menu-btn")
|
||||
return String(($button.data("platform") || state.platform || "PC")).toUpperCase()
|
||||
}
|
||||
|
||||
function setCurrentPlatform(platform) {
|
||||
const nextPlatform = String(platform || "PC").toUpperCase()
|
||||
if (state.platform !== nextPlatform) {
|
||||
state.menus = null
|
||||
state.parentMap = {}
|
||||
}
|
||||
state.platform = nextPlatform
|
||||
return state.platform
|
||||
}
|
||||
|
||||
function filterMenusByPlatform(menus, platform) {
|
||||
const currentPlatform = String(platform || "PC").toUpperCase()
|
||||
return (menus || []).filter(function (menu) {
|
||||
return String(menu.platform || "PC").toUpperCase() === currentPlatform
|
||||
})
|
||||
}
|
||||
|
||||
function setMenus(menus, platform) {
|
||||
state.parentMap = {}
|
||||
state.menus = filterMenusByPlatform(flattenMenus(menus, "", []), platform).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
}
|
||||
|
||||
function getMenus(platform) {
|
||||
platform = String(platform || getCurrentPlatform()).toUpperCase()
|
||||
setCurrentPlatform(platform)
|
||||
const cached = state.menus
|
||||
if (cached && cached.length) {
|
||||
return $.Deferred().resolve(cached).promise()
|
||||
@@ -136,35 +169,22 @@
|
||||
|
||||
const storeMenus = getStoreMenus()
|
||||
if (storeMenus && storeMenus.length) {
|
||||
state.menus = flattenMenus(storeMenus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return $.Deferred().resolve(state.menus).promise()
|
||||
return $.Deferred().resolve(setMenus(storeMenus, platform)).promise()
|
||||
}
|
||||
|
||||
return $.get("/platform/sys/user/getLogonUser").then(function (res) {
|
||||
if (res && res.code === 0 && res.data && res.data.menus) {
|
||||
state.parentMap = {}
|
||||
state.menus = flattenMenus(res.data.menus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
return setMenus(res.data.menus, platform)
|
||||
}
|
||||
const sessionMenus = getSessionMenus()
|
||||
if (sessionMenus && sessionMenus.length) {
|
||||
state.menus = flattenMenus(sessionMenus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
return setMenus(sessionMenus, platform)
|
||||
}
|
||||
return []
|
||||
}, function () {
|
||||
const sessionMenus = getSessionMenus()
|
||||
if (sessionMenus && sessionMenus.length) {
|
||||
state.menus = flattenMenus(sessionMenus, "", []).filter(function (menu) {
|
||||
return menu.href
|
||||
})
|
||||
return state.menus
|
||||
return setMenus(sessionMenus, platform)
|
||||
}
|
||||
return []
|
||||
})
|
||||
@@ -409,7 +429,7 @@
|
||||
})
|
||||
return
|
||||
}
|
||||
getMenus().then(function (menus) {
|
||||
getMenus(getCurrentPlatform()).then(function (menus) {
|
||||
const matches = matchMenus(state.lastText, menus)
|
||||
runAfterRecognitionEnd(function () {
|
||||
chooseMenu(matches)
|
||||
@@ -423,6 +443,7 @@
|
||||
|
||||
function init() {
|
||||
$(document).on("click", "#voice-menu-btn", function () {
|
||||
setCurrentPlatform($(this).data("platform") || "PC")
|
||||
start()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
:on-exceed="handleExceed"
|
||||
:on-remove="handleRemove"
|
||||
:before-upload="beforeUpload"
|
||||
:limit="upload_number"
|
||||
:limit="uploadLimitNumber"
|
||||
:accept="fileAccept"
|
||||
:multiple="true"
|
||||
>
|
||||
@@ -31,7 +31,7 @@
|
||||
:on-remove="handleRemove"
|
||||
:before-upload="beforeUpload"
|
||||
:on-exceed="handleExceed"
|
||||
:limit="upload_number"
|
||||
:limit="uploadLimitNumber"
|
||||
:accept="fileAccept"
|
||||
:multiple="true"
|
||||
list-type="picture-card"
|
||||
@@ -71,7 +71,7 @@
|
||||
:on-remove="handleRemove"
|
||||
:on-exceed="handleExceed"
|
||||
:before-upload="beforeUpload"
|
||||
:limit="upload_number"
|
||||
:limit="uploadLimitNumber"
|
||||
:accept="fileAccept"
|
||||
class="drag-upload"
|
||||
:class="{ 'drag-upload-disabled': uploadMode !== 'pc' }"
|
||||
@@ -123,7 +123,7 @@ module.exports = {
|
||||
},
|
||||
// 上传数量
|
||||
upload_number: {
|
||||
type: Number,
|
||||
type: [Number, String],
|
||||
default: 1,
|
||||
required: false
|
||||
},
|
||||
@@ -198,8 +198,12 @@ module.exports = {
|
||||
action() {
|
||||
return this.upload_result_type === "id" ? this.upload_return_id_api : this.upload_dynamic_return_url_api
|
||||
},
|
||||
uploadLimitNumber() {
|
||||
const number = Number(this.upload_number)
|
||||
return Number.isFinite(number) && number > 0 ? number : 1
|
||||
},
|
||||
upload_tips() {
|
||||
const uploadNumber = this.upload_number
|
||||
const uploadNumber = this.uploadLimitNumber
|
||||
const fileAccept = this.fileAccept
|
||||
const fileSize = this.upload_size
|
||||
|
||||
@@ -359,10 +363,12 @@ module.exports = {
|
||||
|
||||
handleRemove(file, fileList) {
|
||||
if (this.upload_result_category === "interval") {
|
||||
if (this.upload_result_type === "id") {
|
||||
}
|
||||
if (this.upload_result_type === "url") {
|
||||
}
|
||||
const resultIntervalValue = fileList
|
||||
.map((item) => item.response && item.response.data ? item.response.data : item.url || item.data)
|
||||
.filter((item) => item)
|
||||
.join(",")
|
||||
this.$emit("update:value", resultIntervalValue)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.upload_result_category === "array") {
|
||||
@@ -381,13 +387,11 @@ module.exports = {
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.$emit("update:value", fileList)
|
||||
}
|
||||
},
|
||||
|
||||
handleExceed(files, fileList) {
|
||||
this.$message.warning("最多只能上传" + this.upload_number + "个文件")
|
||||
this.$message.warning("最多只能上传" + this.uploadLimitNumber + "个文件")
|
||||
},
|
||||
|
||||
// 上传事件
|
||||
@@ -562,8 +566,8 @@ module.exports = {
|
||||
const originFileList = this.fileList || []
|
||||
console.log(data.files)
|
||||
|
||||
if (this.upload_number) {
|
||||
if (originFileList.length + data.files.length > this.upload_number) {
|
||||
if (this.uploadLimitNumber) {
|
||||
if (originFileList.length + data.files.length > this.uploadLimitNumber) {
|
||||
this.$message.error("上传文件数量超出限制")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<script src="${base!}/components/plugins/sysDict/DictData.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/coordinateUtil.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/voiceMenuNavigator.js"></script>
|
||||
<script src="${base!}/assets/platform/js/main.js"></script>
|
||||
<script src="${base!}/assets/platform/js/mixin/styleMixin.js"></script>
|
||||
<script src="${base!}/assets/platform/js/tool/businessTool.js"></script>
|
||||
@@ -167,10 +168,20 @@
|
||||
func && typeof func === "function" && func()
|
||||
}
|
||||
|
||||
function returnH5Home(activeTab = "home") {
|
||||
if (window.store && typeof window.store.commit === "function") {
|
||||
window.store.commit("setActiveTarBar", activeTab || "home")
|
||||
}
|
||||
window.location.replace("/platform/h5/home")
|
||||
}
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
historyBack: function(func = ()=>{}) {
|
||||
historyBack(func);
|
||||
},
|
||||
returnH5Home: function(activeTab = "home") {
|
||||
returnH5Home(activeTab)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -397,19 +408,49 @@
|
||||
</script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.component("rich-text", httpVueLoader("/components/plugins/sysRichTextView/index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("h5-file-upload", httpVueLoader("/components/plugins/sysUpload/h5Index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("h5-signature", httpVueLoader("/components/plugins/sysSignature/h5Index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("text-editor", httpVueLoader("/components/plugins/sysTextEditor/index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("dict-tag", httpVueLoader("/components/plugins/sysDict/DictTag.vue?v=" + new Date().getTime()))
|
||||
Vue.component("svg-icon", httpVueLoader("/components/plugins/sysSvgIcon/index.vue?v=" + new Date().getTime()))
|
||||
Vue.component("year-van-dropdown-item", httpVueLoader("/components/plugins/vantMore/yearVanDropDownItem.vue?v=" + new Date().getTime()))
|
||||
Vue.component("van-text-dialog", httpVueLoader("/components/plugins/vantMore/vantTextDialog.vue?v=" + new Date().getTime()))
|
||||
Vue.component("enum-tag", httpVueLoader("/components/plugins/sysEnum/EnumTag.vue?v=" + new Date().getTime()))
|
||||
Vue.component("table-list", httpVueLoader("/components/plugins/h5/TableList.vue?v=" + new Date().getTime()))
|
||||
Vue.component("table-column", httpVueLoader("/components/plugins/h5/TableColumn.vue?v=" + new Date().getTime()))
|
||||
Vue.component("file-preview", httpVueLoader("/components/plugins/sysFilePreview/H5Index.vue?v=" + new Date().getTime()))
|
||||
const h5ComponentVersion = "20260524"
|
||||
Vue.component("rich-text", httpVueLoader("/components/plugins/sysRichTextView/index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("h5-file-upload", httpVueLoader("/components/plugins/sysUpload/h5Index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("h5-signature", httpVueLoader("/components/plugins/sysSignature/h5Index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("text-editor", httpVueLoader("/components/plugins/sysTextEditor/index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("dict-tag", httpVueLoader("/components/plugins/sysDict/DictTag.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("svg-icon", httpVueLoader("/components/plugins/sysSvgIcon/index.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("year-van-dropdown-item", httpVueLoader("/components/plugins/vantMore/yearVanDropDownItem.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("van-text-dialog", httpVueLoader("/components/plugins/vantMore/vantTextDialog.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("enum-tag", httpVueLoader("/components/plugins/sysEnum/EnumTag.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("table-list", httpVueLoader("/components/plugins/h5/TableList.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("table-column", httpVueLoader("/components/plugins/h5/TableColumn.vue?v=" + h5ComponentVersion))
|
||||
Vue.component("file-preview", httpVueLoader("/components/plugins/sysFilePreview/H5Index.vue?v=" + h5ComponentVersion))
|
||||
</script>
|
||||
<style>
|
||||
.h5-voice-menu {
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
bottom: calc(76px + env(safe-area-inset-bottom));
|
||||
z-index: 21000;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
background: #1989fa;
|
||||
box-shadow: 0 6px 18px rgba(25, 137, 250, 0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.h5-voice-menu.is-listening {
|
||||
background: #ff976a;
|
||||
box-shadow: 0 6px 18px rgba(255, 151, 106, 0.38);
|
||||
}
|
||||
|
||||
.h5-voice-menu .voice-menu-text {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-page page-showtabbar">
|
||||
@@ -417,6 +458,10 @@
|
||||
<div id="container">${layoutContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="h5-voice-menu" id="voice-menu-btn" data-platform="H5" title="语音打开菜单">
|
||||
<i class="fa fa-microphone"></i>
|
||||
<span class="voice-menu-text">语音</span>
|
||||
</button>
|
||||
<script nonce="${cspNonce!}">
|
||||
toggleShowBar()
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<!doctype html>
|
||||
<html lang="${lang,escape}">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>数智工会领导驾驶舱</title>
|
||||
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/root.css?v=20260524"/>
|
||||
<script src="${base!}/assets/platform/plugins/vue/vue.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/axios/axios.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/jquery/jquery.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js?v=20260524"></script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.config.devtools = false
|
||||
|
||||
const store = {
|
||||
state: {
|
||||
user: JSON.parse(window.sessionStorage.getItem("user") || "null") || {permissions: [], roles: []}
|
||||
}
|
||||
}
|
||||
|
||||
window.ELEMENT = window.ELEMENT || {
|
||||
Message: {
|
||||
error(message) {
|
||||
console.error(message || "操作失败")
|
||||
}
|
||||
},
|
||||
Loading: {
|
||||
service() {
|
||||
return {
|
||||
close() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vue.prototype.$commonUtil = commonUtil
|
||||
Vue.prototype.$auth = commonUtil.authService()
|
||||
Vue.prototype.$axios = commonUtil.axiosService()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
${layoutContent!}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!doctype html>
|
||||
<html lang="${lang,escape}">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"/>
|
||||
<title>智慧工会</title>
|
||||
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/vant/index.css?v=20260524"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/common.css?v=20260524"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/h5.css?v=20260524"/>
|
||||
|
||||
<script src="${base!}/assets/platform/plugins/vue/vue.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/vant/index.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/axios/axios.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/plugins/jquery/jquery.js?v=20260524"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js?v=20260524"></script>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
Vue.config.devtools = true
|
||||
|
||||
if (vant.Form && vant.Form.props && vant.Form.props.showErrorMessage) {
|
||||
vant.Form.props.showErrorMessage.default = false
|
||||
}
|
||||
if (vant.ActionSheet && vant.ActionSheet.props && vant.ActionSheet.props.lazyRender) {
|
||||
vant.ActionSheet.props.lazyRender.default = false
|
||||
}
|
||||
vant.Toast.allowMultiple()
|
||||
if (vant.Lazyload) {
|
||||
Vue.use(vant.Lazyload)
|
||||
}
|
||||
|
||||
window.loadScriptOnce = function(src) {
|
||||
window.__scriptLoadingMap = window.__scriptLoadingMap || {}
|
||||
if (window.__scriptLoadingMap[src]) {
|
||||
return window.__scriptLoadingMap[src]
|
||||
}
|
||||
window.__scriptLoadingMap[src] = new Promise(function(resolve, reject) {
|
||||
const existing = document.querySelector('script[src="' + src + '"]')
|
||||
if (existing) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
const script = document.createElement("script")
|
||||
script.src = src
|
||||
script.onload = function() {
|
||||
resolve()
|
||||
}
|
||||
script.onerror = function() {
|
||||
reject(new Error("script load failed: " + src))
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
return window.__scriptLoadingMap[src]
|
||||
}
|
||||
|
||||
window.loadStyleOnce = function(href) {
|
||||
window.__styleLoadingMap = window.__styleLoadingMap || {}
|
||||
if (window.__styleLoadingMap[href]) {
|
||||
return window.__styleLoadingMap[href]
|
||||
}
|
||||
window.__styleLoadingMap[href] = new Promise(function(resolve, reject) {
|
||||
const existing = document.querySelector('link[href="' + href + '"]')
|
||||
if (existing) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
const link = document.createElement("link")
|
||||
link.rel = "stylesheet"
|
||||
link.href = href
|
||||
link.onload = function() {
|
||||
resolve()
|
||||
}
|
||||
link.onerror = function() {
|
||||
reject(new Error("style load failed: " + href))
|
||||
}
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
return window.__styleLoadingMap[href]
|
||||
}
|
||||
|
||||
const store = {
|
||||
state: {
|
||||
user: JSON.parse(window.sessionStorage.getItem("user") || "null"),
|
||||
room: "${@auth.getPrincipalProperty('loginname')}:${@auth.getSessionId()}",
|
||||
activeTarBar: null
|
||||
},
|
||||
commit(type, payload) {
|
||||
if (type === "setUser") {
|
||||
this.state.user = payload
|
||||
} else if (type === "setActiveTarBar") {
|
||||
this.state.activeTarBar = payload
|
||||
}
|
||||
},
|
||||
dispatch(type) {
|
||||
if (type === "logout") {
|
||||
window.localStorage.removeItem("zhgh-h5-vuex")
|
||||
window.location.href = "/platform/login/logout"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.ELEMENT = window.ELEMENT || {
|
||||
Message: {
|
||||
error(message) {
|
||||
vant.Toast.fail(message || "操作失败")
|
||||
}
|
||||
},
|
||||
Loading: {
|
||||
service() {
|
||||
const loading = vant.Toast.loading({
|
||||
duration: 0,
|
||||
forbidClick: true,
|
||||
message: "处理中,请稍候"
|
||||
})
|
||||
return {
|
||||
close() {
|
||||
loading.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function historyBack(func) {
|
||||
if (window.history.length > 1) {
|
||||
window.history.back()
|
||||
} else {
|
||||
window.location.href = "/platform/h5/home"
|
||||
}
|
||||
func && typeof func === "function" && func()
|
||||
}
|
||||
|
||||
function returnH5Home(activeTab = "home") {
|
||||
store.commit("setActiveTarBar", activeTab || "home")
|
||||
window.location.replace("/platform/h5/home")
|
||||
}
|
||||
|
||||
Vue.mixin({
|
||||
methods: {
|
||||
historyBack: function(func = function(){}) {
|
||||
historyBack(func)
|
||||
},
|
||||
returnH5Home: function(activeTab = "home") {
|
||||
returnH5Home(activeTab)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Vue.prototype.$commonUtil = commonUtil
|
||||
Vue.prototype.$auth = commonUtil.authService()
|
||||
Vue.prototype.$axios = commonUtil.axiosService()
|
||||
Vue.prototype.$downLoad = commonUtil.downLoadService.bind(commonUtil)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-page">
|
||||
<div class="page-wrapper">
|
||||
<div id="container">${layoutContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -709,7 +709,7 @@
|
||||
</div>
|
||||
|
||||
<div class="v4-user-section">
|
||||
<button type="button" class="v4-voice-menu" id="voice-menu-btn" title="语音打开菜单">
|
||||
<button type="button" class="v4-voice-menu" id="voice-menu-btn" data-platform="PC" title="语音打开菜单">
|
||||
<i class="fa fa-microphone"></i>
|
||||
<span class="voice-menu-text">语音</span>
|
||||
</button>
|
||||
|
||||
@@ -1513,7 +1513,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
<div class="oa-hero-section">
|
||||
<!-- 背景图 -->
|
||||
<div class="oa-background-image">
|
||||
<img src="${config.AppHomeImg!}" alt=""/>
|
||||
<img :src="homeBannerList[0] || ''" alt=""/>
|
||||
</div>
|
||||
|
||||
<!-- 搜索和统计区域 -->
|
||||
@@ -2020,6 +2020,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
recommendServices: [],
|
||||
favoriteItems: [],
|
||||
recommendApps: [],
|
||||
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item),
|
||||
|
||||
// 工会网站新闻
|
||||
websiteNews: {},
|
||||
|
||||
@@ -73,7 +73,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
<!-- 首页banner -->
|
||||
<div class="section-banner">
|
||||
<div class="banner-img">
|
||||
<img src="${config.AppHomeImg!}" alt=""/>
|
||||
<img :src="homeBannerList[0] || ''" alt=""/>
|
||||
<stats></stats>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,6 +87,8 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<work-template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"></work-template>
|
||||
|
||||
<jcdt :list="websiteNews"></jcdt>
|
||||
</div>
|
||||
|
||||
@@ -94,6 +96,7 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("act.js"){}#-->
|
||||
<!--#include("template.js"){}#-->
|
||||
<!--#include("jcdt.js"){}#-->
|
||||
<!--#include("entry.js"){}#-->
|
||||
<!--#include("user.js"){}#-->
|
||||
@@ -104,11 +107,13 @@ layout("/layouts/v4/baseLayout.html"){
|
||||
el: '#v4-home-app',
|
||||
data(){
|
||||
return{
|
||||
websiteNews: []
|
||||
websiteNews: [],
|
||||
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'act': act,
|
||||
'work-template': workTemplate,
|
||||
'jcdt': jcdt,
|
||||
'entry': entry,
|
||||
'user': user,
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
const workTemplate = {
|
||||
template: /*language=HTML*/ `
|
||||
<div class="section-wrapper work-template-wrapper">
|
||||
<div class="work-template-header">
|
||||
<div class="work-template-title">
|
||||
<i class="fa fa-clipboard"></i>
|
||||
<span>工作模板</span>
|
||||
<em>/Templates</em>
|
||||
</div>
|
||||
</div>
|
||||
<div class="work-template-card">
|
||||
<div v-if="templateList && templateList.length > 0" class="work-template-grid">
|
||||
<div class="work-template-item"
|
||||
v-for="template in templateList"
|
||||
:key="template.id"
|
||||
@click="go(template)">
|
||||
<div class="work-template-icon">
|
||||
<img :src="template.templateIcon || template.cover || 'https://www.ncu.edu.cn/__local/8/52/2C/644986B4C9A030F7B65300178A6_8679CB08_18467.jpg'"
|
||||
alt="">
|
||||
</div>
|
||||
<div class="work-template-name">{{ template.templateName || template.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="no-activity-placeholder">
|
||||
<div class="icon"><i class="fa fa-clipboard"></i></div>
|
||||
<p>暂无工作模板</p>
|
||||
<p class="subtext">敬请关注后续更新</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
templateList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
listTemplate() {
|
||||
this.$axios.post("/platform/home/listHomeTemplate").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.templateList = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
go(template) {
|
||||
if (!template.url) {
|
||||
this.$message.warning("管理员未配置模板链接")
|
||||
return
|
||||
}
|
||||
const url = new URL(template.url, window.location.origin)
|
||||
if (!url.searchParams.get("mode")) {
|
||||
url.searchParams.set("mode", "edit")
|
||||
}
|
||||
if (!url.searchParams.get("id") && template.id) {
|
||||
url.searchParams.set("id", template.id)
|
||||
}
|
||||
window.localStorage.setItem("zhgh_home_template_edit", JSON.stringify({
|
||||
path: url.pathname,
|
||||
id: url.searchParams.get("id"),
|
||||
expiresAt: Date.now() + 60000
|
||||
}))
|
||||
window.open(url.href)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.listTemplate()
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.work-template-wrapper {
|
||||
width: 80%;
|
||||
margin: 20px auto 28px;
|
||||
}
|
||||
|
||||
.work-template-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.work-template-title {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
color: #19324d;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.work-template-title i {
|
||||
color: #409eff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.work-template-title em {
|
||||
color: #b5c0d6;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.work-template-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #edf1f7;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||
min-height: 116px;
|
||||
padding: 18px 20px;
|
||||
}
|
||||
|
||||
.work-template-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
|
||||
justify-items: center;
|
||||
justify-content: start;
|
||||
gap: 12px 18px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.work-template-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.work-template-item:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.work-template-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.work-template-icon img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.work-template-name {
|
||||
min-height: 34px;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
word-break: break-word;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
color: #94a3b8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder .icon {
|
||||
font-size: 44px;
|
||||
margin-bottom: 12px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder p {
|
||||
margin: 4px 0 0;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.work-template-wrapper .no-activity-placeholder .subtext {
|
||||
font-size: 13px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.work-template-grid {
|
||||
grid-template-columns: repeat(3, minmax(72px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.work-template-item {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.work-template-grid {
|
||||
grid-template-columns: repeat(2, minmax(72px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
`
|
||||
};
|
||||
@@ -75,8 +75,9 @@ layout("/layouts/platform.html"){
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="configValue" label="参数值">
|
||||
<template v-if="formData.configKey === 'AppLogo' || formData.configKey === 'AppHomeImg'">
|
||||
<template v-if="formData.configKey === 'AppLogo'">
|
||||
<file-upload
|
||||
key="AppLogo"
|
||||
style="--upload-width: 214px;--upload-height:64px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
@@ -84,8 +85,43 @@ layout("/layouts/platform.html"){
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span v-if="formData.configKey === 'AppLogo'">最佳分辨率:428 x 128</span>
|
||||
<span v-else-if="formData.configKey === 'AppHomeImg'">最佳分辨率:2756 x 732</span>
|
||||
<span>最佳分辨率:428 x 128</span>
|
||||
</template>
|
||||
<template v-else-if="formData.configKey === 'AppHomeImg'">
|
||||
<file-upload
|
||||
key="AppHomeImg"
|
||||
style="--upload-width: 214px;--upload-height:64px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="10"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span>最佳分辨率:2756 x 732,最多可上传 10 张,首页按上传顺序轮播</span>
|
||||
</template>
|
||||
<template v-else-if="formData.configKey === 'AppFeaturedActivityImg'">
|
||||
<file-upload
|
||||
key="AppFeaturedActivityImg"
|
||||
style="--upload-width: 214px;--upload-height:96px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span>最佳分辨率:750 x 280,精彩活动页顶部图片</span>
|
||||
</template>
|
||||
<template v-else-if="formData.configKey === 'AppFestivalBenefitImg'">
|
||||
<file-upload
|
||||
key="AppFestivalBenefitImg"
|
||||
style="--upload-width: 214px;--upload-height:96px"
|
||||
:value.sync="formData.configValue"
|
||||
:upload_number="1"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
<span>最佳分辨率:750 x 280,节日福利页顶部图片</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div v-if="'true'===formData.configValue||'false'===formData.configValue">
|
||||
@@ -179,6 +215,7 @@ layout("/layouts/platform.html"){
|
||||
doEdit: function () {
|
||||
var self = this
|
||||
var url = base + "/platform/sys/conf/editDo"
|
||||
self.normalizeConfigValue()
|
||||
self.$refs["editForm"].validate(function (valid) {
|
||||
if (valid) {
|
||||
$.post(
|
||||
@@ -204,6 +241,41 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
normalizeConfigValue: function () {
|
||||
if (Array.isArray(this.formData.configValue)) {
|
||||
this.formData.configValue = this.formData.configValue
|
||||
.map(function (item) {
|
||||
if (typeof item === "string") {
|
||||
return item
|
||||
}
|
||||
if (item && item.response && item.response.data) {
|
||||
return item.response.data
|
||||
}
|
||||
if (item && item.url) {
|
||||
return item.url
|
||||
}
|
||||
if (item && item.data) {
|
||||
return item.data
|
||||
}
|
||||
return ""
|
||||
})
|
||||
.filter(function (item) {
|
||||
return item
|
||||
})
|
||||
.join(",")
|
||||
}
|
||||
if (typeof this.formData.configValue === "string") {
|
||||
this.formData.configValue = this.formData.configValue
|
||||
.split(",")
|
||||
.map(function (item) {
|
||||
return item.trim()
|
||||
})
|
||||
.filter(function (item) {
|
||||
return item
|
||||
})
|
||||
.join(",")
|
||||
}
|
||||
},
|
||||
pageOrder: function (column) {
|
||||
//按字段排序
|
||||
this.pageForm.pageOrderName = column.prop
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="名称" prop="name">
|
||||
<el-input v-model="pageForm.name" clearable placeholder="请输入名称"></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
<el-card shadow="never">
|
||||
<el-table :data="tableData" header-align="center" border style="width: 100%">
|
||||
<el-table-column label="序号" type="index" width="50px" :index="indexMethod"></el-table-column>
|
||||
<el-table-column label="模板名称" prop="templateName" width="260px">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-model="scope.row.templateName"
|
||||
size="mini"
|
||||
clearable
|
||||
placeholder="请输入模板名称"
|
||||
@change="updateTemplateName(scope.row)">
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" prop="name"></el-table-column>
|
||||
<el-table-column label="PC端链接" prop="url" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="模板图标" prop="templateIcon" width="120px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<file-upload
|
||||
class="template-icon-upload"
|
||||
:upload_number="1"
|
||||
:value="scope.row.templateIcon"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
upload_result_type="url"
|
||||
upload_result_category="interval"
|
||||
upload_mode="image"
|
||||
@update:value="onTemplateIconChange(scope.row, $event)">
|
||||
</file-upload>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否置顶" prop="top" width="100px">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" v-if="scope.row.top" type="success">是</el-tag>
|
||||
<el-tag size="mini" v-else type="info">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关联类路径" prop="classPath" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="状态" prop="enable" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<i v-if="!scope.row.enable" class="fa fa-circle text-danger ml5"></i>
|
||||
<i v-else class="fa fa-circle text-success ml5"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180px">
|
||||
<template slot-scope="scope">
|
||||
<el-link type="danger" size="mini" @click="disable(scope.row.id)" v-if="scope.row.enable">关闭</el-link>
|
||||
<el-link type="primary" size="mini" @click="enable(scope.row.id)" v-if="!scope.row.enable">开启</el-link>
|
||||
<el-link type="primary" size="mini" @click="topUp(scope.row.id)" v-if="!scope.row.top">置顶</el-link>
|
||||
<el-link type="danger" size="mini" @click="cancelTopUp(scope.row.id)" v-if="scope.row.top">取消置顶</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
disable(id) {
|
||||
this.$confirm("您确定要关闭吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/disable", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
enable(id) {
|
||||
this.$confirm("您确定要开启吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/enable", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
topUp(id) {
|
||||
this.$confirm("您确定要置顶吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/topUp", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
cancelTopUp(id) {
|
||||
this.$confirm("您确定要取消置顶吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios.post(loc() + "/cancelTopUp", {id}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
updateTemplateName(row) {
|
||||
this.$axios.post(loc() + "/updateTemplateName", {
|
||||
id: row.id,
|
||||
templateName: row.templateName
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
onTemplateIconChange(row, templateIcon) {
|
||||
if (templateIcon === undefined && !row.templateIcon) {
|
||||
return
|
||||
}
|
||||
row.templateIcon = templateIcon
|
||||
this.updateTemplateIcon(row)
|
||||
},
|
||||
updateTemplateIcon(row) {
|
||||
this.$nextTick(() => {
|
||||
this.$axios.post(loc() + "/updateTemplateIcon", {
|
||||
id: row.id,
|
||||
templateIcon: row.templateIcon
|
||||
}).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.template-icon-upload {
|
||||
--upload-width: 48px;
|
||||
--upload-height: 48px;
|
||||
}
|
||||
|
||||
.template-icon-upload .el-upload-list--picture-card .el-upload-list__item,
|
||||
.template-icon-upload .el-upload--picture-card {
|
||||
width: 48px !important;
|
||||
height: 48px !important;
|
||||
line-height: 48px !important;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.template-icon-upload .el-upload--picture-card i {
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -949,39 +949,44 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
return data
|
||||
},
|
||||
async init(id) {
|
||||
if (id) {
|
||||
this.activeName = "1"
|
||||
this.findOne(id)
|
||||
} else {
|
||||
this.formData = {
|
||||
time: [],
|
||||
applyTime2: [],
|
||||
plannedDate: [],
|
||||
goods: [],
|
||||
billFiles: [],
|
||||
photoFiles: [],
|
||||
otherFiles: [],
|
||||
tissuePersonList: [],
|
||||
unionUserNumberLimit: [],
|
||||
signUpMethod: null,
|
||||
rangerMeter: 100,
|
||||
isEnrollSystem: true,
|
||||
isPushHome: 0,
|
||||
isIntegral: false
|
||||
this.formLoading = true
|
||||
try {
|
||||
if (id) {
|
||||
this.activeName = "1"
|
||||
await this.findOne(id)
|
||||
} else {
|
||||
this.formData = {
|
||||
time: [],
|
||||
applyTime2: [],
|
||||
plannedDate: [],
|
||||
goods: [],
|
||||
billFiles: [],
|
||||
photoFiles: [],
|
||||
otherFiles: [],
|
||||
tissuePersonList: [],
|
||||
unionUserNumberLimit: [],
|
||||
signUpMethod: null,
|
||||
rangerMeter: 100,
|
||||
isEnrollSystem: true,
|
||||
isPushHome: 0,
|
||||
isIntegral: false
|
||||
}
|
||||
this.generateActivityCode().then((data) => {
|
||||
this.$set(this.formData, "activityCode", data)
|
||||
})
|
||||
this.getUnionData().then((data) => {
|
||||
this.$set(this.formData, "unionUserNumberLimit", data)
|
||||
})
|
||||
}
|
||||
this.generateActivityCode().then((data) => {
|
||||
this.$set(this.formData, "activityCode", data)
|
||||
})
|
||||
this.getUnionData().then((data) => {
|
||||
this.$set(this.formData, "unionUserNumberLimit", data)
|
||||
this.clubOptions = await this.getClubsByRole()
|
||||
this.clubOptions.map((v) => {
|
||||
v.name = v.clubName
|
||||
})
|
||||
const units = await this.$businessTool.listUnit()
|
||||
this.unitOptions = this.clubOptions.concat(units)
|
||||
} finally {
|
||||
this.formLoading = false
|
||||
}
|
||||
this.clubOptions = await this.getClubsByRole()
|
||||
this.clubOptions.map((v) => {
|
||||
v.name = v.clubName
|
||||
})
|
||||
const units = await this.$businessTool.listUnit()
|
||||
this.unitOptions = this.clubOptions.concat(units)
|
||||
},
|
||||
async queryUserByIds(ids) {
|
||||
const {data} = await this.$axios.post("/platform/activity/culture/applyActivity/queryUserByIds", {ids: JSON.stringify(ids)})
|
||||
@@ -1018,6 +1023,14 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
this.bizId = row.id
|
||||
this.activeName = "1"
|
||||
this.init(row.id)
|
||||
},
|
||||
openUrlEdit() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
const mode = params.get("mode")
|
||||
const id = params.get("id")
|
||||
if (mode === "edit" && id) {
|
||||
this.openEdit({id})
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@@ -1030,5 +1043,8 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
})
|
||||
this.getActivityGroup()
|
||||
// this.init()
|
||||
},
|
||||
mounted() {
|
||||
this.openUrlEdit()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,18 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
撤回
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item :command="{type:'delete',row}"
|
||||
<el-dropdown-item
|
||||
v-if="activity_type === 40001 && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
|
||||
:command="{type:'setTemplate',row}">
|
||||
设为模板
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="activity_type === 40001 && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
|
||||
:command="{type:'cancelTemplate',row}">
|
||||
取消模板
|
||||
</el-dropdown-item>
|
||||
|
||||
<el-dropdown-item :command="{type:'delete',row}" :disabled="!!row.isTemplate"
|
||||
v-if="(activity_type === 40001 && (row.taskKey === 'startTask' || !row.instanceId)) || (activity_type !== 40001 && $auth.hasRole('SYSADMIN'))" >
|
||||
删除
|
||||
</el-dropdown-item>
|
||||
@@ -209,6 +220,10 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
this.onRevoke(row)
|
||||
} else if (type === "delete") {
|
||||
this.doDelete(row)
|
||||
} else if (type === "setTemplate") {
|
||||
this.setTemplate(row)
|
||||
} else if (type === "cancelTemplate") {
|
||||
this.cancelTemplate(row)
|
||||
} else if (type === "openCode") {
|
||||
this.url = location.origin + "/platform/h5/activity/culture/signUp?id=" + row.id + "&groupId=" + row.groupId
|
||||
this.codeDialogVisible = true
|
||||
@@ -231,6 +246,10 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
})
|
||||
},
|
||||
doDelete(row) {
|
||||
if (row.isTemplate) {
|
||||
this.$message.warning("该活动已设为模板,请先取消模板后再删除")
|
||||
return
|
||||
}
|
||||
const {id} = row
|
||||
this.$confirm("确定要删除该活动吗?", "提示", {type: "warning"}).then(async () => {
|
||||
this.$set(row, "loading", true)
|
||||
@@ -244,6 +263,40 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
this.$set(row, "loading", false)
|
||||
})
|
||||
},
|
||||
setTemplate(row) {
|
||||
this.$confirm("确定将该活动设为工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
this.$set(row, "loading", true)
|
||||
const resp = await this.$axios.post("/platform/activity/culture/infoManage/setTemplate", {id: row.id})
|
||||
if (resp.code === 0) {
|
||||
this.doSearch()
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
this.$set(row, "loading", false)
|
||||
})
|
||||
},
|
||||
cancelTemplate(row) {
|
||||
this.$confirm("确定取消该活动的工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
this.$set(row, "loading", true)
|
||||
const resp = await this.$axios.post("/platform/activity/culture/infoManage/cancelTemplate", {id: row.id})
|
||||
if (resp.code === 0) {
|
||||
this.doSearch()
|
||||
this.$message.success(resp.msg)
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
this.$set(row, "loading", false)
|
||||
})
|
||||
},
|
||||
onRevoke(row) {
|
||||
this.$confirm("您确定要撤回吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
@@ -268,7 +321,8 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
}
|
||||
})
|
||||
this.tableLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
async created() {
|
||||
// 根据 activity_type 动态添加流程相关列
|
||||
@@ -279,5 +333,5 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
);
|
||||
}
|
||||
this.pageData()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -656,7 +656,7 @@
|
||||
async applyUserModelInput(val) {
|
||||
if (val === 2) {
|
||||
if (!this.eventForm.unionLimit || this.eventForm.unionLimit.length === 0) {
|
||||
const resp = await $.get(loc() + "/getUnionLimit", { activityScopeId: this.eventForm.activityGroupId })
|
||||
const resp = await $.get("/platform/activity/sports/info/mange/getUnionLimit", { activityScopeId: this.eventForm.activityGroupId })
|
||||
if (resp.code === 0) {
|
||||
this.$set(this.eventForm, "unionLimit", resp.data)
|
||||
}
|
||||
@@ -736,7 +736,7 @@
|
||||
spinner: "el-icon-loading",
|
||||
background: "rgba(0,0,0,.45)"
|
||||
})
|
||||
const resp = await this.$axios.post(loc() + "/doAssignmentDate", {
|
||||
const resp = await this.$axios.post("/platform/activity/sports/info/mange/doAssignmentDate", {
|
||||
eventIds: JSON.stringify(this.checkedEventInfo.map((v) => v.id)),
|
||||
events: JSON.stringify(this.checkedEventInfo)
|
||||
})
|
||||
@@ -1043,7 +1043,7 @@
|
||||
},
|
||||
async operate() {
|
||||
const deleteEventIds = this.eventsIds.filter((v) => !this.formData.eventsIds.includes(v))
|
||||
const { data } = await $.get(loc() + "/getEventApply", {
|
||||
const { data } = await $.get("/platform/activity/sports/info/mange/getEventApply", {
|
||||
activityId: this.formData.id,
|
||||
eventId: JSON.stringify(deleteEventIds)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<div slot="header">
|
||||
<div class="sports-new-actions">
|
||||
<el-button @click="doSave" type="primary">保 存</el-button>
|
||||
<el-button @click="doOperate" type="primary">提 交</el-button>
|
||||
<!--<el-button @click="back">返 回</el-button>-->
|
||||
</div>
|
||||
</div>
|
||||
<add-activity
|
||||
:is_a06="$auth.hasRole('SCHOOL_UNION_ADMIN')"
|
||||
:is_club="$auth.hasRole('CLUB_PRESIDENT')"
|
||||
:is_sysadmin="$auth.hasRole('SYSADMIN')"
|
||||
ref="addActivity"
|
||||
@flip="flip"
|
||||
@flush="flush">
|
||||
</add-activity>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("/platform/zhgh/activity/sports/infoManage/addActivity.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"add-activity": ACTIVITY_SPORTS_ADD_ACTIVITY
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
commonUtil.pjaxPush("/platform/activity/sports/info/mange")
|
||||
},
|
||||
flip() {
|
||||
this.back()
|
||||
},
|
||||
flush() {
|
||||
},
|
||||
async doOperate() {
|
||||
await this.$refs.addActivity.operate()
|
||||
},
|
||||
async doSave() {
|
||||
await this.$refs.addActivity.doSave()
|
||||
},
|
||||
initForm() {
|
||||
const mode = GetQueryString("mode")
|
||||
const id = GetQueryString("id")
|
||||
if (mode === "edit" && id) {
|
||||
this.$refs.addActivity.openEdit({id}, true)
|
||||
} else {
|
||||
this.$refs.addActivity.openAdd()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initForm()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.sports-new-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,58 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.el-drawer__body {
|
||||
padding: 20px;
|
||||
}
|
||||
.my-drawer .el-col-4 {
|
||||
text-align: right;
|
||||
}
|
||||
.my-drawer .el-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.courseTimeButton {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<basic-form ref="formRef" @back="back" @refresh="refresh"></basic-form>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("/platform/zhgh/activity/trainSignUp/manage/basicForm.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["USER_CAMPUS", "TRAIN_SIGNUP_TYPE"],
|
||||
components: {
|
||||
"basic-form": basicForm
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
commonUtil.pjaxPush("/platform/trainSignUp/manage")
|
||||
},
|
||||
refresh() {
|
||||
},
|
||||
initForm() {
|
||||
const mode = GetQueryString("mode")
|
||||
const id = GetQueryString("id")
|
||||
const row = mode === "edit" && id ? {id} : undefined
|
||||
this.$refs.formRef.initData(row)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.initForm()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#include('courseTime.js'){}#-->
|
||||
<!--#include('customForm.js'){}#-->
|
||||
<!--#include('/platform/zhgh/activity/trainSignUp/manage/courseTime.js'){}#-->
|
||||
<!--#include('/platform/zhgh/activity/trainSignUp/manage/customForm.js'){}#-->
|
||||
const basicForm = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
|
||||
@@ -92,7 +92,13 @@ layout("/layouts/platform.html"){
|
||||
<el-dropdown-item @click.native="makeCode(row)">签到二维码</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="onView(row)">查看</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="openEdit(row)">编辑</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="onDelete(row)">删除</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
|
||||
@click.native="setTemplate(row)">设为模板</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
|
||||
@click.native="cancelTemplate(row)">取消模板</el-dropdown-item>
|
||||
<el-dropdown-item :disabled="!!row.isTemplate" @click.native="onDelete(row)">删除</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
@@ -154,9 +160,25 @@ layout("/layouts/platform.html"){
|
||||
],
|
||||
codeDialogVisible: false,
|
||||
activityUrl: '',
|
||||
urlEditInitialized: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pageData(data = null) {
|
||||
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
|
||||
this.tableLoading = true
|
||||
return this.$axios.post(address, data ? data : this.pageForm).then((res) => {
|
||||
this.tableLoading = false
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
this.$nextTick(() => {
|
||||
this.openUrlEdit()
|
||||
})
|
||||
}
|
||||
return res
|
||||
})
|
||||
},
|
||||
back() {
|
||||
this.$refs.guava.index()
|
||||
},
|
||||
@@ -170,6 +192,25 @@ layout("/layouts/platform.html"){
|
||||
this.$refs.formRef.initData(row)
|
||||
})
|
||||
},
|
||||
openUrlEdit() {
|
||||
if (this.urlEditInitialized) {
|
||||
return
|
||||
}
|
||||
const mode = GetQueryString("mode")
|
||||
const id = GetQueryString("id")
|
||||
if (mode !== "edit" || !id) {
|
||||
return
|
||||
}
|
||||
if (!this.$refs.guava) {
|
||||
this.$nextTick(() => {
|
||||
this.openUrlEdit()
|
||||
})
|
||||
return
|
||||
}
|
||||
this.urlEditInitialized = true
|
||||
const row = (this.tableData || []).find(item => item.id === id) || { id }
|
||||
this.openEdit(row)
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.infoRef.initData(row.id)
|
||||
@@ -191,18 +232,56 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
async onDelete(row) {
|
||||
if (row.isTemplate) {
|
||||
this.$message.warning("该活动已设为模板,请先取消模板后再删除")
|
||||
return
|
||||
}
|
||||
this.$confirm("此操作将永久删除, 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/onDelete", { id: row.id })
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
async setTemplate(row) {
|
||||
this.$confirm("确定将该活动设为工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/setTemplate", { id: row.id })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
async cancelTemplate(row) {
|
||||
this.$confirm("确定取消该活动的工作模板吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post(loc() + "/cancelTemplate", { id: row.id })
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
mounted() {
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -242,7 +242,7 @@ let ASSSET_FORM = {
|
||||
this.searchAssetUseUser(this.formData.assetUseUserId)
|
||||
},
|
||||
assetUseUnionIdChange(val) {
|
||||
const union = this.unions.find(v => v.id === val)
|
||||
const union = this.unionList.find(v => v.id === val)
|
||||
if (union) {
|
||||
this.$set(this.formData, "assetUseUnionName", union.name)
|
||||
} else {
|
||||
@@ -260,16 +260,16 @@ let ASSSET_FORM = {
|
||||
},
|
||||
// 点击责任人
|
||||
assetUseUserIdChange(val) {
|
||||
const {
|
||||
unionname,
|
||||
unionid
|
||||
} = this.assetUseUserOption.find(v => v.id === val)
|
||||
this.formData.assetUseUnionId = unionid
|
||||
const user = this.assetUseUserOption.find(v => v.id === val)
|
||||
if (!user) return
|
||||
const unionId = user.unionId || user.unionid
|
||||
const unionName = user.unionName || user.unionname
|
||||
this.formData.assetUseUnionId = unionId
|
||||
if (this.formData.assetTypeCode === 1) {
|
||||
this.formData.assetUseUnionName = "校工会"
|
||||
} else {
|
||||
|
||||
this.formData.assetUseUnionName = unionname
|
||||
this.formData.assetUseUnionName = unionName
|
||||
}
|
||||
},
|
||||
// 点击开始使用日期🧄预计报废时间
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
const form = {
|
||||
template: /*language=HTML*/ `
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" :close-on-click-modal="false">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="80px">
|
||||
<el-form-item label="单位" prop="unitName">
|
||||
<el-input v-model="formData.unitName" placeholder="请输入单位" maxlength="100"
|
||||
show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" :close-on-click-modal="false" width="60%">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="110px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="当前工会" prop="unionName">
|
||||
<el-input v-model="formData.unionName" disabled placeholder="当前登录人所在工会"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="当前单位" prop="unitName">
|
||||
<el-input v-model="formData.unitName" disabled placeholder="当前登录人所在单位"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="地点" prop="address">
|
||||
<el-input v-model="formData.address" placeholder="请输入地点" maxlength="100"
|
||||
show-word-limit></el-input>
|
||||
@@ -21,6 +29,28 @@ const form = {
|
||||
<el-form-item label="开放时间" prop="openTime">
|
||||
<el-input v-model="formData.openTime" placeholder="请输入开放时间"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="图片/视频资料" prop="mediaFiles">
|
||||
<file-upload
|
||||
:value.sync="formData.mediaFiles"
|
||||
:upload_number="10"
|
||||
upload_mode="drag"
|
||||
upload_result_category="array"
|
||||
complete_result
|
||||
:accept="mediaAccept">
|
||||
</file-upload>
|
||||
</el-form-item>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地图X坐标" prop="mapX">
|
||||
<el-input v-model="formData.mapX" disabled placeholder="请通过坐标按钮采集"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地图Y坐标" prop="mapY">
|
||||
<el-input v-model="formData.mapY" disabled placeholder="请通过坐标按钮采集"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
@@ -32,8 +62,11 @@ const form = {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
formData: {},
|
||||
currentUserOrg: {},
|
||||
mediaAccept: ".jpg,.jpeg,.png,.mp4,.mov",
|
||||
rules: {
|
||||
unitName: [{ required: true, message: "请输入单位", trigger: "blur" }],
|
||||
unitName: [{ required: true, message: "未获取到当前单位", trigger: "blur" }],
|
||||
unionName: [{ required: true, message: "未获取到当前工会", trigger: "blur" }],
|
||||
address: [{ required: true, message: "请输入地点", trigger: "blur" }],
|
||||
area: [{ required: true, message: "请输入面积", trigger: "blur" }],
|
||||
facility: [{ required: true, message: "请输入设施", trigger: "blur" }],
|
||||
@@ -42,18 +75,22 @@ const form = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(id) {
|
||||
async onOpen(id) {
|
||||
this.dialogVisible = true
|
||||
this.resetForm()
|
||||
await this.loadCurrentUserOrg()
|
||||
if (id) {
|
||||
this.dialogVisible = true
|
||||
this.resetForm()
|
||||
$.post("/platform/buildHome/littleHouse/detail/" + id).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.formData = resp.data
|
||||
this.formData = Object.assign({}, this.currentUserOrg, resp.data, {
|
||||
mediaFiles: this.parseFiles(resp.data.mediaFiles)
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.dialogVisible = true
|
||||
this.formData = {}
|
||||
this.formData = Object.assign({}, this.currentUserOrg, {
|
||||
mediaFiles: []
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.$refs.formRef.clearValidate()
|
||||
})
|
||||
@@ -67,10 +104,41 @@ const form = {
|
||||
}
|
||||
})
|
||||
},
|
||||
async loadCurrentUserOrg() {
|
||||
const resp = await $.post("/platform/buildHome/littleHouse/currentUserOrg")
|
||||
if (resp.code === 0) {
|
||||
this.currentUserOrg = resp.data || {}
|
||||
}
|
||||
},
|
||||
parseFiles(value) {
|
||||
if (!value) return []
|
||||
if (Array.isArray(value)) return value
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
},
|
||||
getFileExt(file) {
|
||||
const name = file.name || file.url || file.response?.data || file.data || ""
|
||||
const index = name.lastIndexOf(".")
|
||||
return index > -1 ? name.substring(index + 1).toLowerCase() : ""
|
||||
},
|
||||
validateMediaFiles(files) {
|
||||
const acceptExts = this.mediaAccept.split(",").map(v => v.replace(".", "").toLowerCase())
|
||||
return (files || []).every(file => acceptExts.includes(this.getFileExt(file)))
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
$.post("/platform/buildHome/littleHouse/save", this.formData).then((resp) => {
|
||||
if (!this.validateMediaFiles(this.formData.mediaFiles)) {
|
||||
this.$message.warning("仅支持上传 jpg、jpeg、png、mp4、mov 格式文件")
|
||||
return
|
||||
}
|
||||
const data = Object.assign({}, this.formData, {
|
||||
mediaFiles: JSON.stringify(this.formData.mediaFiles || [])
|
||||
})
|
||||
$.post("/platform/buildHome/littleHouse/save", data).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.$emit("refresh")
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="单位名称">
|
||||
<el-input placeholder="单位名称" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
<search-item label="单位/工会名称">
|
||||
<el-input placeholder="单位/工会名称" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
@@ -18,6 +17,7 @@ layout("/layouts/platform.html"){
|
||||
</table-tool>
|
||||
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
|
||||
<el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index" width="80px"></el-table-column>
|
||||
<el-table-column label="工会" prop="unionName" sortable width="220px" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="单位" prop="unitName" sortable width="200px"></el-table-column>
|
||||
<el-table-column label="活动场所基本情况">
|
||||
<el-table-column label="地点" prop="address" sortable width="200px"></el-table-column>
|
||||
@@ -25,8 +25,9 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column label="设施" prop="facility" sortable></el-table-column>
|
||||
<el-table-column label="开放时间" prop="openTime" sortable width="200px"></el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="200px">
|
||||
<el-table-column label="操作" fixed="right" width="280px">
|
||||
<template scope="{row}">
|
||||
<el-button v-if="$auth.hasRole('SYSADMIN')" size="mini" type="warning" @click="openCoordinate(row)">坐标</el-button>
|
||||
<el-button size="mini" type="primary" @click="$refs.littleHouseFormRef.onOpen(row.id)">修改</el-button>
|
||||
<el-button size="mini" type="danger" @click="onDelete(row.id)">删除</el-button>
|
||||
</template>
|
||||
@@ -37,6 +38,7 @@ layout("/layouts/platform.html"){
|
||||
</guava>
|
||||
|
||||
<little-house-form ref="littleHouseFormRef" @refresh="doSearch"></little-house-form>
|
||||
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
@@ -63,12 +65,78 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
})
|
||||
},
|
||||
openCoordinate(row) {
|
||||
if (!row || !row.id) {
|
||||
this.$message.warning("\u672a\u83b7\u53d6\u5230\u5c0f\u5bb6\u8bb0\u5f55")
|
||||
return
|
||||
}
|
||||
if (this.hasCoordinate(row)) {
|
||||
this.$confirm(
|
||||
"\u5f53\u524d\u8bb0\u5f55\u5df2\u6709\u5750\u6807\uff0c\u662f\u4fee\u6539\u8fd8\u662f\u6e05\u7a7a\uff1f",
|
||||
"\u63d0\u793a",
|
||||
{
|
||||
type: "warning",
|
||||
distinguishCancelAndClose: true,
|
||||
confirmButtonText: "\u4fee\u6539\u5750\u6807",
|
||||
cancelButtonText: "\u6e05\u7a7a\u5750\u6807"
|
||||
}
|
||||
).then(() => {
|
||||
this.doOpenCoordinate(row)
|
||||
}).catch((action) => {
|
||||
if (action === "cancel") {
|
||||
this.clearCoordinate(row)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
this.doOpenCoordinate(row)
|
||||
},
|
||||
hasCoordinate(row) {
|
||||
return row
|
||||
&& row.mapX !== null
|
||||
&& row.mapX !== undefined
|
||||
&& row.mapX !== ""
|
||||
&& row.mapY !== null
|
||||
&& row.mapY !== undefined
|
||||
&& row.mapY !== ""
|
||||
},
|
||||
doOpenCoordinate(row) {
|
||||
const params = [
|
||||
"coordinateMode=1",
|
||||
"houseId=" + encodeURIComponent(row.id),
|
||||
"t=" + Date.now()
|
||||
]
|
||||
window.open("/platform/careData/leader?" + params.join("&"), "_blank")
|
||||
},
|
||||
clearCoordinate(row) {
|
||||
$.post("/platform/buildHome/littleHouse/clearCoordinate", { id: row.id }).then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success("\u5750\u6807\u5df2\u6e05\u7a7a")
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
},
|
||||
handleCoordinateMessage(event) {
|
||||
if (event.origin !== window.location.origin) {
|
||||
return
|
||||
}
|
||||
const data = event.data || {}
|
||||
if (data.type !== "littleHouseCoordinateSaved") {
|
||||
return
|
||||
}
|
||||
this.$message.success("\u5750\u6807\u91c7\u96c6\u6210\u529f")
|
||||
this.doSearch()
|
||||
},
|
||||
onExport() {
|
||||
this.$downLoad("/platform/buildHome/littleHouse/exportXlsx")
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("message", this.handleCoordinateMessage)
|
||||
this.pageData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("message", this.handleCoordinateMessage)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<script src="${base!}/assets/platform/plugins/echarts/echarts.min.js?v=20260527"></script>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.asset-data-panel {
|
||||
position: absolute;
|
||||
left: 1.35%;
|
||||
top: 69.6%;
|
||||
width: 20.82%;
|
||||
height: 28.06%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/asset-data-panel.png?v=20260527") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.asset-data-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.asset-data-chart {
|
||||
position: absolute;
|
||||
left: 3%;
|
||||
top: 14%;
|
||||
width: 94%;
|
||||
height: 74%;
|
||||
}
|
||||
|
||||
.asset-data-note {
|
||||
position: absolute;
|
||||
left: 8%;
|
||||
right: 8%;
|
||||
bottom: 4.5%;
|
||||
overflow: hidden;
|
||||
color: #315d86;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.asset-data-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 48%;
|
||||
z-index: 2;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="asset-data-panel">
|
||||
<div class="asset-data-title">资产数据</div>
|
||||
<div ref="usageChart" class="asset-data-chart"></div>
|
||||
<div class="asset-data-empty" v-if="!chartRows.length">暂无数据</div>
|
||||
<div class="asset-data-note">不同颜色代表不同使用状况</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "\u9000\u51fa\u5168\u5c4f" : "\u5168\u5c4f\u663e\u793a" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
chart: null,
|
||||
chartRows: [],
|
||||
fullscreen: false,
|
||||
chartColors: ["#1c8df4", "#35c982", "#f3a64f", "#8a7cff", "#f05d80", "#2ec7c9", "#b6a2de"]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadAssetData()
|
||||
},
|
||||
mounted() {
|
||||
this.initChart()
|
||||
window.addEventListener("resize", this.resizeChart)
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("resize", this.resizeChart)
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
if (this.chart) {
|
||||
this.chart.dispose()
|
||||
this.chart = null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initChart() {
|
||||
if (!window.echarts || !this.$refs.usageChart) {
|
||||
return
|
||||
}
|
||||
this.chart = echarts.init(this.$refs.usageChart)
|
||||
this.renderChart()
|
||||
},
|
||||
loadAssetData() {
|
||||
this.$axios.post("/platform/careData/leader/assetDataData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.chartRows = (data.states || [])
|
||||
.map(item => ({
|
||||
name: item.name || "\u672a\u586b\u5199",
|
||||
value: Number(item.value || 0)
|
||||
}))
|
||||
.filter(item => item.value > 0)
|
||||
this.renderChart()
|
||||
})
|
||||
},
|
||||
renderChart() {
|
||||
if (!this.chart) {
|
||||
return
|
||||
}
|
||||
const total = this.chartRows.reduce((sum, item) => sum + item.value, 0)
|
||||
this.chart.setOption({
|
||||
color: this.chartColors,
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{b}<br/>{c} ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
orient: "vertical",
|
||||
right: "3%",
|
||||
top: "24%",
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 9,
|
||||
textStyle: {
|
||||
color: "#315d86",
|
||||
fontSize: 12,
|
||||
lineHeight: 14
|
||||
},
|
||||
formatter(name) {
|
||||
return name.length > 5 ? name.slice(0, 5) + "..." : name
|
||||
}
|
||||
},
|
||||
graphic: {
|
||||
type: "text",
|
||||
left: "28%",
|
||||
top: "47%",
|
||||
style: {
|
||||
text: total ? total + "\n\u4ef6" : "",
|
||||
fill: "#1683f4",
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
textAlign: "center"
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
name: "\u4f7f\u7528\u72b6\u51b5",
|
||||
type: "pie",
|
||||
radius: ["32%", "56%"],
|
||||
center: ["32%", "52%"],
|
||||
avoidLabelOverlap: true,
|
||||
minAngle: 8,
|
||||
itemStyle: {
|
||||
borderColor: "rgba(255,255,255,0.9)",
|
||||
borderWidth: 2
|
||||
},
|
||||
label: {
|
||||
color: "#244769",
|
||||
fontSize: 11,
|
||||
formatter: "{d}%"
|
||||
},
|
||||
labelLine: {
|
||||
length: 8,
|
||||
length2: 4,
|
||||
lineStyle: {
|
||||
color: "rgba(36, 71, 105, 0.55)"
|
||||
}
|
||||
},
|
||||
data: this.chartRows
|
||||
}]
|
||||
}, true)
|
||||
},
|
||||
resizeChart() {
|
||||
if (this.chart) {
|
||||
this.chart.resize()
|
||||
}
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,257 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.base-union-panel {
|
||||
position: absolute;
|
||||
right: calc(1.55% - 2px);
|
||||
top: calc(60.05% + 95px);
|
||||
width: calc(28.2% - 140px);
|
||||
height: 28.1%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/base-union-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.base-union-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.base-union-list {
|
||||
position: absolute;
|
||||
left: calc(8.5% - 15px);
|
||||
top: 20.2%;
|
||||
width: calc(83% + 35px);
|
||||
height: 68.5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.base-union-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.base-union-list::-webkit-scrollbar-track {
|
||||
background: rgba(110, 178, 237, 0.22);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.base-union-list::-webkit-scrollbar-thumb {
|
||||
background: rgba(49, 142, 231, 0.76);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.base-union-row {
|
||||
position: relative;
|
||||
flex: 0 0 17.2%;
|
||||
height: 17.2%;
|
||||
min-height: 31px;
|
||||
background-position: center center;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
color: #244769;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.base-union-row:nth-child(2n + 1) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-a.png?v=20260526");
|
||||
}
|
||||
|
||||
.base-union-row:nth-child(2n) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-b.png?v=20260526");
|
||||
}
|
||||
|
||||
.base-union-name {
|
||||
position: absolute;
|
||||
left: 18%;
|
||||
top: 50%;
|
||||
width: 52%;
|
||||
overflow: hidden;
|
||||
transform: translateY(-50%);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.base-union-count {
|
||||
position: absolute;
|
||||
right: 9.5%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #1d82e8;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.base-union-count span {
|
||||
margin-left: 3px;
|
||||
color: #4e6d8d;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.base-union-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 48%;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="base-union-panel">
|
||||
<div class="base-union-title">基层工会</div>
|
||||
<div class="base-union-list" v-if="displayUnions.length">
|
||||
<div class="base-union-row" v-for="item in displayUnions" :key="item.unionCode || item.id">
|
||||
<div class="base-union-name" :title="item.unionname">{{ item.unionname || "--" }}</div>
|
||||
<div class="base-union-count">{{ item.value || 0 }}<span>人</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="base-union-empty" v-else>暂无数据</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
unions: [],
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayUnions() {
|
||||
return this.unions
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadBaseUnionData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadBaseUnionData() {
|
||||
this.$axios.post("/platform/careData/leader/baseUnionData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.unions = data.unions || []
|
||||
})
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,252 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.club-panel {
|
||||
position: absolute;
|
||||
right: calc(1.55% - 3px);
|
||||
top: calc(38.2% + 3px);
|
||||
width: calc(28.2% - 145px);
|
||||
height: 28.1%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/base-union-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.club-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-list {
|
||||
position: absolute;
|
||||
left: calc(8.5% - 14px);
|
||||
top: 20.2%;
|
||||
width: calc(83% + 29px);
|
||||
height: 68.5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.club-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.club-list::-webkit-scrollbar-track {
|
||||
background: rgba(110, 178, 237, 0.22);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.club-list::-webkit-scrollbar-thumb {
|
||||
background: rgba(49, 142, 231, 0.76);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.club-row {
|
||||
position: relative;
|
||||
flex: 0 0 17.2%;
|
||||
height: 17.2%;
|
||||
min-height: 31px;
|
||||
background-position: center center;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
color: #244769;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.club-row:nth-child(2n + 1) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-a.png?v=20260526");
|
||||
}
|
||||
|
||||
.club-row:nth-child(2n) {
|
||||
background-image: url("${base!}/assets/platform/images/careData/leader/base-union-row-b.png?v=20260526");
|
||||
}
|
||||
|
||||
.club-name {
|
||||
position: absolute;
|
||||
left: 18%;
|
||||
top: 50%;
|
||||
width: 52%;
|
||||
overflow: hidden;
|
||||
transform: translateY(-50%);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-count {
|
||||
position: absolute;
|
||||
right: 9.5%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #1d82e8;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.club-count span {
|
||||
margin-left: 3px;
|
||||
color: #4e6d8d;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.club-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 48%;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="club-panel">
|
||||
<div class="club-title">协会社团</div>
|
||||
<div class="club-list" v-if="clubs.length">
|
||||
<div class="club-row" v-for="item in clubs" :key="item.clubCode || item.id">
|
||||
<div class="club-name" :title="item.clubName">{{ item.clubName || "--" }}</div>
|
||||
<div class="club-count">{{ item.value || 0 }}<span>人</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="club-empty" v-else>暂无数据</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
clubs: [],
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadClubData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadClubData() {
|
||||
this.$axios.post("/platform/careData/leader/clubData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.clubs = data.clubs || []
|
||||
})
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,282 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.condolence-panel {
|
||||
position: absolute;
|
||||
left: calc(1.35% - 5px);
|
||||
top: calc(38.9% - 28px);
|
||||
width: calc(20.82% - 6px);
|
||||
height: calc(27.65% + 70px);
|
||||
background: url("${base!}/assets/platform/images/careData/leader/condolence-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.condolence-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.condolence-chart {
|
||||
position: absolute;
|
||||
left: 4%;
|
||||
top: calc(18% + 10px);
|
||||
width: 92%;
|
||||
height: 72%;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-around;
|
||||
padding: 2.5% 2.2% 7.5%;
|
||||
}
|
||||
|
||||
.condolence-bar-item {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 16%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.condolence-value {
|
||||
position: absolute;
|
||||
bottom: calc(17% + var(--bar-height) + 5px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: #243f5d;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 14px;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.condolence-bar {
|
||||
position: absolute;
|
||||
bottom: 17%;
|
||||
left: 50%;
|
||||
width: 42%;
|
||||
height: var(--bar-height);
|
||||
min-height: 0;
|
||||
transform: translateX(-50%);
|
||||
background: linear-gradient(180deg, rgba(95, 183, 255, 0.96), rgba(35, 126, 238, 0.88));
|
||||
border: 1px solid rgba(208, 241, 255, 0.66);
|
||||
box-shadow: inset 0 0 10px rgba(215, 244, 255, 0.4), 0 0 10px rgba(58, 152, 245, 0.46);
|
||||
}
|
||||
|
||||
.condolence-bar-item:nth-child(2n) .condolence-bar {
|
||||
background: linear-gradient(180deg, rgba(90, 219, 162, 0.94), rgba(40, 177, 103, 0.86));
|
||||
box-shadow: inset 0 0 10px rgba(224, 255, 239, 0.36), 0 0 10px rgba(54, 190, 118, 0.36);
|
||||
}
|
||||
|
||||
.condolence-bar-item:nth-child(3) .condolence-bar {
|
||||
background: linear-gradient(180deg, rgba(255, 183, 109, 0.94), rgba(229, 132, 66, 0.86));
|
||||
box-shadow: inset 0 0 10px rgba(255, 236, 211, 0.34), 0 0 10px rgba(227, 142, 76, 0.36);
|
||||
}
|
||||
|
||||
.condolence-label {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
width: 56px;
|
||||
overflow: hidden;
|
||||
transform: translateX(-50%);
|
||||
color: #244769;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.68);
|
||||
}
|
||||
|
||||
.condolence-empty {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 43%;
|
||||
color: rgba(36, 71, 105, 0.82);
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="condolence-panel">
|
||||
<div class="condolence-title">慰问汇总</div>
|
||||
<div class="condolence-chart">
|
||||
<div class="condolence-empty" v-if="!hasData">暂无数据</div>
|
||||
<div class="condolence-bar-item" v-for="item in displayTypes" :key="item.index" :style="{ '--bar-height': barHeight(item) }">
|
||||
<div class="condolence-value">{{ item.rate || "0%" }}</div>
|
||||
<div class="condolence-bar"></div>
|
||||
<div class="condolence-label" :title="item.name">{{ shortName(item.name) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
types: [],
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasData() {
|
||||
return this.types.some(item => Number(item.count || 0) > 0)
|
||||
},
|
||||
maxCount() {
|
||||
return Math.max(...this.types.map(item => Number(item.count || 0)), 0)
|
||||
},
|
||||
displayTypes() {
|
||||
const rows = this.types.slice(0, 5)
|
||||
while (rows.length < 5) {
|
||||
rows.push({
|
||||
index: rows.length + 1,
|
||||
name: "",
|
||||
rate: "0%",
|
||||
rateValue: 0
|
||||
})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadCondolenceData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadCondolenceData() {
|
||||
this.$axios.post("/platform/careData/leader/condolenceData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.types = data.types || []
|
||||
})
|
||||
},
|
||||
shortName(name) {
|
||||
if (!name) {
|
||||
return "--"
|
||||
}
|
||||
return name.length > 4 ? name.slice(0, 4) : name
|
||||
},
|
||||
barHeight(item) {
|
||||
const count = Number(item.count || 0)
|
||||
if (count <= 0 || this.maxCount <= 0) {
|
||||
return "0%"
|
||||
}
|
||||
return Math.min(76, Math.max(8, count / this.maxCount * 76)) + "%"
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,248 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.data-metric-panel {
|
||||
position: absolute;
|
||||
right: calc(1.55% - 2px);
|
||||
top: 8.2%;
|
||||
width: calc(28.2% - 140px);
|
||||
height: 28.1%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/data-metric-panel.png?v=20260527") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.data-metric-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-metric-graph {
|
||||
position: absolute;
|
||||
left: calc(8% + 5px);
|
||||
top: 21%;
|
||||
width: calc(84% + 5px);
|
||||
height: calc(66% + 20px);
|
||||
background: url("${base!}/assets/platform/images/careData/leader/data-metric-graph.png?v=20260527") center center / contain no-repeat;
|
||||
}
|
||||
|
||||
.data-metric-point {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 28%;
|
||||
min-width: 62px;
|
||||
transform: translate(-50%, -50%);
|
||||
color: #1c79dc;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
text-align: center;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.9), 0 0 10px rgba(72, 168, 255, 0.42);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.data-metric-point-center {
|
||||
width: 34%;
|
||||
}
|
||||
|
||||
.data-metric-label {
|
||||
margin-top: 2px;
|
||||
overflow: hidden;
|
||||
color: #315d86;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-metric-value {
|
||||
overflow: hidden;
|
||||
color: #1683f4;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 17px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.data-metric-point-center .data-metric-value {
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
}
|
||||
|
||||
.data-metric-unit {
|
||||
margin-left: 2px;
|
||||
color: #4e6d8d;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="data-metric-panel">
|
||||
<div class="data-metric-title">数据指标</div>
|
||||
<div class="data-metric-graph">
|
||||
<div
|
||||
class="data-metric-point"
|
||||
v-for="item in dataMetricPoints"
|
||||
:key="item.key"
|
||||
:class="{ 'data-metric-point-center': item.center }"
|
||||
:style="{ left: item.left, top: item.top }">
|
||||
<div class="data-metric-value">{{ item.value }}<span class="data-metric-unit">{{ item.unit }}</span></div>
|
||||
<div class="data-metric-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "退出全屏" : "全屏显示" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
dataMetric: {},
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dataMetricPoints() {
|
||||
return [
|
||||
{key: "tourCount", label: "\u7597\u4f11\u517b\u4eba\u6570", value: this.displayNumber(this.dataMetric.tourCount), unit: "\u4eba", left: "12%", top: "19%"},
|
||||
{key: "honorCount", label: "\u52b3\u6a21\u5148\u8fdb", value: this.displayNumber(this.dataMetric.honorCount), unit: "\u4eba", left: "88%", top: "19%"},
|
||||
{key: "difficultCount", label: "\u56f0\u96be\u4eba\u6570", value: this.displayNumber(this.dataMetric.difficultCount), unit: "\u4eba", left: "12%", top: "74%"},
|
||||
{key: "reimburseTotal", label: "\u62a5\u9500\u603b\u6570", value: this.displayMoneyWan(this.dataMetric.reimburseTotal), unit: "\u4e07\u5143", left: "88%", top: "74%"},
|
||||
{key: "budgetTotal", label: "\u9884\u7b97\u603b\u989d", value: this.displayMoneyWan(this.dataMetric.budgetTotal), unit: "\u4e07\u5143", left: "50%", top: "50%", center: true}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadDataMetricData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadDataMetricData() {
|
||||
this.$axios.post("/platform/careData/leader/dataMetricData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
this.dataMetric = res.data || {}
|
||||
})
|
||||
},
|
||||
displayNumber(value) {
|
||||
return Number(value || 0)
|
||||
},
|
||||
displayMoneyWan(value) {
|
||||
const amount = Number(value || 0) / 10000
|
||||
if (amount >= 100) {
|
||||
return Math.round(amount).toString()
|
||||
}
|
||||
if (amount >= 10) {
|
||||
return amount.toFixed(1).replace(/\.0$/, "")
|
||||
}
|
||||
return amount.toFixed(2).replace(/\.?0+$/, "")
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,599 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #071b36;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.leader-screen {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
min-width: 1280px;
|
||||
min-height: 720px;
|
||||
overflow: hidden;
|
||||
color: #eaf7ff;
|
||||
background:
|
||||
radial-gradient(circle at 50% 45%, rgba(255, 255, 255, 0.62) 0, rgba(135, 202, 255, 0.4) 26%, transparent 58%),
|
||||
linear-gradient(135deg, #74b8f2 0%, #9acbfb 48%, #6aaee9 100%);
|
||||
}
|
||||
|
||||
.leader-screen::before,
|
||||
.leader-screen::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leader-screen::before {
|
||||
border: 2px solid rgba(219, 245, 255, 0.58);
|
||||
box-shadow: inset 0 0 34px rgba(24, 126, 220, 0.34);
|
||||
}
|
||||
|
||||
.leader-screen::after {
|
||||
background:
|
||||
linear-gradient(rgba(255, 255, 255, 0.16) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.12) 1px, transparent 1px);
|
||||
background-size: 78px 78px;
|
||||
mask-image: radial-gradient(circle at 50% 50%, #000 0, transparent 76%);
|
||||
}
|
||||
|
||||
.screen-header {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: 82px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.screen-header::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 22%;
|
||||
right: 22%;
|
||||
height: 72px;
|
||||
border: 2px solid rgba(216, 246, 255, 0.58);
|
||||
border-top: none;
|
||||
border-radius: 0 0 88px 88px;
|
||||
background: linear-gradient(180deg, rgba(39, 144, 255, 0.42), rgba(27, 110, 205, 0.12));
|
||||
box-shadow: 0 12px 28px rgba(23, 94, 180, 0.28), inset 0 -12px 24px rgba(159, 230, 255, 0.36);
|
||||
}
|
||||
|
||||
.screen-title {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
color: #f8fdff;
|
||||
font-size: 36px;
|
||||
line-height: 58px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 0 10px rgba(40, 140, 232, 0.9);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.weather-box,
|
||||
.time-box {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
z-index: 3;
|
||||
color: rgba(255, 255, 255, 0.94);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.weather-box {
|
||||
left: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 35% 35%, #ffe599, #ff9d32 58%, #74c8ff 60%, #d9f4ff 100%);
|
||||
box-shadow: 0 0 14px rgba(255, 207, 99, 0.45);
|
||||
}
|
||||
|
||||
.time-box {
|
||||
right: 28px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.screen-body {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: calc(100vh - 92px);
|
||||
padding: 6px 26px 22px;
|
||||
display: grid;
|
||||
grid-template-columns: 400px minmax(520px, 1fr) 400px;
|
||||
grid-template-rows: 300px 1fr 300px;
|
||||
gap: 18px 22px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
border: 1px solid rgba(232, 249, 255, 0.62);
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(77, 162, 229, 0.08));
|
||||
box-shadow: inset 0 0 24px rgba(255, 255, 255, 0.18), 0 10px 28px rgba(25, 103, 183, 0.16);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel::before,
|
||||
.panel::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
width: 42px;
|
||||
height: 2px;
|
||||
background: #ffe078;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.panel::before {
|
||||
left: 7px;
|
||||
}
|
||||
|
||||
.panel::after {
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #f8fdff;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(90deg, rgba(31, 126, 238, 0.18), rgba(54, 159, 255, 0.62), rgba(31, 126, 238, 0.18));
|
||||
text-shadow: 0 0 8px rgba(60, 150, 240, 0.78);
|
||||
}
|
||||
|
||||
.proposal-panel {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px 20px;
|
||||
padding: 18px 16px 14px;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
position: relative;
|
||||
height: 62px;
|
||||
padding: 10px 12px 9px 70px;
|
||||
border: 1px solid rgba(227, 248, 255, 0.42);
|
||||
background: linear-gradient(90deg, rgba(231, 248, 255, 0.34), rgba(139, 205, 255, 0.12));
|
||||
box-shadow: inset 0 -8px 12px rgba(32, 124, 218, 0.16);
|
||||
}
|
||||
|
||||
.metric-item::after {
|
||||
content: "↑";
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
bottom: 8px;
|
||||
color: rgba(47, 142, 224, 0.72);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 12px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, #f4fbff 0, #55c8ff 42%, rgba(34, 139, 227, 0.16) 68%);
|
||||
box-shadow: 0 0 14px rgba(77, 187, 255, 0.7);
|
||||
}
|
||||
|
||||
.metric-icon::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 11px;
|
||||
right: 11px;
|
||||
top: 9px;
|
||||
height: 14px;
|
||||
border-radius: 2px;
|
||||
background: #1d97e6;
|
||||
box-shadow: -7px 9px 0 -2px #1d97e6, 7px 9px 0 -2px #1d97e6;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
color: rgba(38, 74, 112, 0.86);
|
||||
font-size: 14px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
margin-top: 3px;
|
||||
color: #1677d8;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.metric-value small {
|
||||
margin-left: 3px;
|
||||
color: rgba(49, 93, 132, 0.76);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.center-map {
|
||||
grid-column: 2;
|
||||
grid-row: 1 / 3;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.orbit {
|
||||
position: absolute;
|
||||
width: min(78%, 760px);
|
||||
aspect-ratio: 1;
|
||||
border: 1px dashed rgba(255, 255, 255, 0.6);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 60px rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.map-shape {
|
||||
position: relative;
|
||||
width: min(76%, 760px);
|
||||
height: min(58%, 430px);
|
||||
border-radius: 46% 54% 47% 53% / 38% 45% 55% 62%;
|
||||
background:
|
||||
radial-gradient(circle at 74% 33%, rgba(243, 251, 255, 0.95) 0, rgba(68, 168, 255, 0.88) 22%, transparent 23%),
|
||||
radial-gradient(circle at 50% 52%, #5fb3ff 0, #2786f0 58%, #1b69cf 100%);
|
||||
box-shadow: 0 18px 38px rgba(35, 115, 210, 0.36), 0 0 38px rgba(255, 255, 255, 0.6);
|
||||
opacity: 0.88;
|
||||
}
|
||||
|
||||
.map-shape::before,
|
||||
.map-shape::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
background: rgba(37, 129, 232, 0.9);
|
||||
box-shadow: 0 0 22px rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
.map-shape::before {
|
||||
right: -62px;
|
||||
top: 92px;
|
||||
width: 120px;
|
||||
height: 132px;
|
||||
border-radius: 42% 58% 55% 45%;
|
||||
}
|
||||
|
||||
.map-shape::after {
|
||||
right: 42px;
|
||||
bottom: -42px;
|
||||
width: 55px;
|
||||
height: 82px;
|
||||
border-radius: 50%;
|
||||
transform: rotate(18deg);
|
||||
}
|
||||
|
||||
.center-session {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: rgba(20, 76, 134, 0.8);
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder-list {
|
||||
padding: 18px 22px;
|
||||
}
|
||||
|
||||
.placeholder-row {
|
||||
display: grid;
|
||||
grid-template-columns: 34px 1fr 48px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
height: 40px;
|
||||
color: rgba(39, 73, 111, 0.82);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.placeholder-index {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
background: rgba(58, 151, 236, 0.72);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.placeholder-track {
|
||||
height: 5px;
|
||||
background: rgba(255, 255, 255, 0.38);
|
||||
}
|
||||
|
||||
.placeholder-bar {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #41c79f, #3a96ec);
|
||||
}
|
||||
|
||||
.right-circle {
|
||||
height: calc(100% - 40px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.circle-core {
|
||||
width: 128px;
|
||||
height: 128px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
background: radial-gradient(circle, #e8fbff 0, #42bbff 45%, #1f75da 100%);
|
||||
box-shadow: 0 0 30px rgba(38, 135, 230, 0.46);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.circle-core strong {
|
||||
font-size: 34px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bottom-nav {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 14px;
|
||||
transform: translateX(-50%);
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
.nav-dot {
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(238, 251, 255, 0.72);
|
||||
background: radial-gradient(circle, #ecfbff 0, #59bfff 52%, #2675d4 100%);
|
||||
box-shadow: 0 0 18px rgba(32, 126, 220, 0.42);
|
||||
}
|
||||
|
||||
@media (max-width: 1500px) {
|
||||
.screen-body {
|
||||
grid-template-columns: 360px minmax(480px, 1fr) 360px;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
gap: 12px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="leader-screen" v-cloak>
|
||||
<header class="screen-header">
|
||||
<div class="weather-box">
|
||||
<span class="weather-icon"></span>
|
||||
<span>智慧工会 · 领导驾驶舱</span>
|
||||
</div>
|
||||
<h1 class="screen-title">数智工会领导驾驶舱</h1>
|
||||
<div class="time-box">
|
||||
<div>{{ currentDate }}</div>
|
||||
<div>{{ currentTime }}</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="screen-body">
|
||||
<section class="panel proposal-panel">
|
||||
<div class="panel-title">提案征集与办理</div>
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">提案总数</div>
|
||||
<div class="metric-value">{{ overview.total || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">立案数量</div>
|
||||
<div class="metric-value">{{ overview.filedCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">意见建议梳理</div>
|
||||
<div class="metric-value">{{ overview.suggestionCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">不予立案</div>
|
||||
<div class="metric-value">{{ overview.rejectedCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">办结数量</div>
|
||||
<div class="metric-value">{{ overview.doneCount || 0 }}<small>件</small></div>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-icon"></span>
|
||||
<div class="metric-label">满意率</div>
|
||||
<div class="metric-value">{{ overview.satisfiedRate || '0%' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="center-map">
|
||||
<div class="center-session">{{ session.fullName || '当前届次' }}</div>
|
||||
<div class="orbit"></div>
|
||||
<div class="map-shape"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">专题指标总览</div>
|
||||
<div class="right-circle">
|
||||
<div class="circle-core">
|
||||
<strong>{{ overview.total || 0 }}</strong>
|
||||
<span>提案指标</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">办理进度排行</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="(item, index) in progressRows" :key="item.name">
|
||||
<span class="placeholder-index">{{ pad(index + 1) }}</span>
|
||||
<div>
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="placeholder-track"><div class="placeholder-bar" :style="{width: item.rate}"></div></div>
|
||||
</div>
|
||||
<span>{{ item.rate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">专题模块预留</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="(item, index) in reserveRows" :key="item">
|
||||
<span class="placeholder-index">{{ pad(index + 1) }}</span>
|
||||
<div>{{ item }}</div>
|
||||
<span>待接入</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">数据趋势预留</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="item in trendRows" :key="item.name">
|
||||
<span class="placeholder-index">{{ item.index }}</span>
|
||||
<div>
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="placeholder-track"><div class="placeholder-bar" :style="{width: item.rate}"></div></div>
|
||||
</div>
|
||||
<span>{{ item.rate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="panel-title">重点数据预留</div>
|
||||
<div class="placeholder-list">
|
||||
<div class="placeholder-row" v-for="item in keyRows" :key="item.name">
|
||||
<span class="placeholder-index">{{ item.index }}</span>
|
||||
<div>{{ item.name }}</div>
|
||||
<span>{{ item.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<nav class="bottom-nav">
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
<span class="nav-dot"></span>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
timer: null,
|
||||
currentDate: "",
|
||||
currentTime: "",
|
||||
session: {},
|
||||
overview: {},
|
||||
progressRows: [
|
||||
{name: "提案征集", rate: "87%"},
|
||||
{name: "立案办理", rate: "82%"},
|
||||
{name: "承办答复", rate: "68%"},
|
||||
{name: "结果反馈", rate: "43%"},
|
||||
{name: "满意评价", rate: "36%"}
|
||||
],
|
||||
reserveRows: ["职工关爱专题", "工会经费专题", "活动服务专题", "荣誉建设专题"],
|
||||
trendRows: [
|
||||
{index: "01", name: "年度提案趋势", rate: "78%"},
|
||||
{index: "02", name: "办理效率趋势", rate: "64%"},
|
||||
{index: "03", name: "满意度趋势", rate: "72%"}
|
||||
],
|
||||
keyRows: [
|
||||
{index: "01", name: "专题指标标题", value: "256"},
|
||||
{index: "02", name: "专题指标标题", value: "205"},
|
||||
{index: "03", name: "专题指标标题", value: "123"}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.updateTime()
|
||||
this.timer = setInterval(this.updateTime, 1000)
|
||||
this.loadProposalData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
methods: {
|
||||
loadProposalData() {
|
||||
this.$axios.post("/platform/careData/leader/proposalData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.session = data.session || {}
|
||||
this.overview = data.overview || {}
|
||||
})
|
||||
},
|
||||
updateTime() {
|
||||
const now = new Date()
|
||||
const week = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][now.getDay()]
|
||||
this.currentDate = now.getFullYear() + "-" + this.pad(now.getMonth() + 1) + "-" + this.pad(now.getDate()) + " " + week
|
||||
this.currentTime = this.pad(now.getHours()) + ":" + this.pad(now.getMinutes()) + ":" + this.pad(now.getSeconds())
|
||||
},
|
||||
pad(value) {
|
||||
return String(value).padStart(2, "0")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,142 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
position: absolute;
|
||||
min-width: 86px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #1b83e9;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.75);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.metric-value::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -2px -8px;
|
||||
z-index: -1;
|
||||
background: rgba(189, 224, 252, 0.54);
|
||||
filter: blur(3px);
|
||||
}
|
||||
|
||||
.metric-value small {
|
||||
margin-left: 3px;
|
||||
color: rgba(43, 105, 159, 0.82);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.metric-total {
|
||||
left: 5.8%;
|
||||
top: 16.7%;
|
||||
}
|
||||
|
||||
.metric-filed {
|
||||
left: 15.9%;
|
||||
top: 16.7%;
|
||||
}
|
||||
|
||||
.metric-suggestion {
|
||||
left: 5.8%;
|
||||
top: 24.2%;
|
||||
}
|
||||
|
||||
.metric-rejected {
|
||||
left: 15.9%;
|
||||
top: 24.2%;
|
||||
}
|
||||
|
||||
.metric-done {
|
||||
left: 5.8%;
|
||||
top: 31.7%;
|
||||
}
|
||||
|
||||
.metric-satisfied {
|
||||
left: 15.9%;
|
||||
top: 31.7%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<div class="metric-value metric-total">{{ displayNumber(overview.total) }}<small>件</small></div>
|
||||
<div class="metric-value metric-filed">{{ displayNumber(overview.filedCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-suggestion">{{ displayNumber(overview.suggestionCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-rejected">{{ displayNumber(overview.rejectedCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-done">{{ displayNumber(overview.doneCount) }}<small>件</small></div>
|
||||
<div class="metric-value metric-satisfied">{{ overview.satisfiedRate || "0%" }}</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
overview: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadProposalData()
|
||||
},
|
||||
methods: {
|
||||
loadProposalData() {
|
||||
this.$axios.post("/platform/careData/leader/proposalData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.overview = data.overview || {}
|
||||
})
|
||||
},
|
||||
displayNumber(value) {
|
||||
return Number(value || 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,260 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.proposal-panel {
|
||||
position: absolute;
|
||||
left: 1.35%;
|
||||
top: 8.2%;
|
||||
width: 20.82%;
|
||||
height: 27.65%;
|
||||
background: url("${base!}/assets/platform/images/careData/leader/proposal-panel.png?v=20260526") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.proposal-title {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.3%;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.proposal-card-grid {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.proposal-card {
|
||||
position: absolute;
|
||||
width: 44%;
|
||||
height: 19.2%;
|
||||
background: var(--card-bg) center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.proposal-card-total {
|
||||
left: calc(4.3% - 2px);
|
||||
top: 18.5%;
|
||||
}
|
||||
|
||||
.proposal-card-filed {
|
||||
left: 51.7%;
|
||||
top: 18.5%;
|
||||
}
|
||||
|
||||
.proposal-card-total {
|
||||
height: calc(25.6% + 3px);
|
||||
}
|
||||
|
||||
.proposal-card-filed {
|
||||
height: calc(25.6% + 2px);
|
||||
}
|
||||
|
||||
.proposal-card-suggestion {
|
||||
left: calc(4.3% - 1px);
|
||||
top: calc(41.3% + 10px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-card-rejected {
|
||||
left: calc(51.7% + 2px);
|
||||
top: calc(41.3% + 10px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-card-done {
|
||||
left: calc(4.3% - 1px);
|
||||
top: calc(65.2% + 20px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-card-satisfied {
|
||||
left: 51.7%;
|
||||
top: calc(65.2% + 20px);
|
||||
height: calc(19.8% + 20px);
|
||||
}
|
||||
|
||||
.proposal-label {
|
||||
position: absolute;
|
||||
left: 38.5%;
|
||||
top: 20%;
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
color: #304f70;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
letter-spacing: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.proposal-value {
|
||||
position: absolute;
|
||||
left: calc(38.5% + 23px);
|
||||
top: 48%;
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
color: #1683f4;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
line-height: 17px;
|
||||
letter-spacing: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="proposal-panel">
|
||||
<div class="proposal-title">提案征集和办理</div>
|
||||
<div class="proposal-card-grid">
|
||||
<article class="proposal-card" v-for="item in proposalMetrics" :key="item.key" :class="'proposal-card-' + item.key" :style="{ '--card-bg': 'url(' + item.bg + ')' }">
|
||||
<div class="proposal-label">{{ item.label }}</div>
|
||||
<div class="proposal-value">{{ item.value }}</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "\u9000\u51fa\u5168\u5c4f" : "\u5168\u5c4f\u663e\u793a" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
overview: {},
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
proposalMetrics() {
|
||||
const imagePath = "${base!}/assets/platform/images/careData/leader/"
|
||||
return [
|
||||
{key: "total", label: "\u63d0\u6848\u603b\u6570", value: this.displayNumber(this.overview.total), bg: imagePath + "proposal-card-total.png?v=20260526"},
|
||||
{key: "filed", label: "\u7acb\u6848\u6570\u91cf", value: this.displayNumber(this.overview.filedCount), bg: imagePath + "proposal-card-filed.png?v=20260526"},
|
||||
{key: "suggestion", label: "\u610f\u89c1\u5efa\u8bae", value: this.displayNumber(this.overview.suggestionCount), bg: imagePath + "proposal-card-suggestion.png?v=20260526"},
|
||||
{key: "rejected", label: "\u4e0d\u4e88\u7acb\u6848", value: this.displayNumber(this.overview.rejectedCount), bg: imagePath + "proposal-card-rejected.png?v=20260526"},
|
||||
{key: "done", label: "\u529e\u7ed3\u6570\u91cf", value: this.displayNumber(this.overview.doneCount), bg: imagePath + "proposal-card-done.png?v=20260526"},
|
||||
{key: "satisfied", label: "\u6ee1\u610f\u7387", value: this.overview.satisfiedRate || "0%", bg: imagePath + "proposal-card-satisfied.png?v=20260526"}
|
||||
]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadProposalData()
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
loadProposalData() {
|
||||
this.$axios.post("/platform/careData/leader/proposalData").then(res => {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
const data = res.data || {}
|
||||
this.overview = data.overview || {}
|
||||
})
|
||||
},
|
||||
displayNumber(value) {
|
||||
return Number(value || 0)
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,173 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_leader_dashboard.html"){
|
||||
#-->
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
font-family: "Microsoft YaHei", "Microsoft JhengHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
[v-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dashboard-wrap {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: #050f1f;
|
||||
}
|
||||
|
||||
.dashboard-stage {
|
||||
position: relative;
|
||||
width: min(100vw, calc(100vh * 16 / 9));
|
||||
height: min(100vh, calc(100vw * 9 / 16));
|
||||
background: url("${base!}/assets/platform/images/careData/leader/leader-bg.jpg?v=20260524") center center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.staff-home-panel {
|
||||
position: absolute;
|
||||
left: 24.1%;
|
||||
top: 22.5%;
|
||||
width: 53.1%;
|
||||
height: 63.5%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.staff-home-title {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
min-width: 168px;
|
||||
height: 30px;
|
||||
padding: 0 28px;
|
||||
transform: translateX(-50%);
|
||||
background: linear-gradient(90deg, rgba(78, 161, 246, 0.08), rgba(79, 169, 255, 0.88), rgba(78, 161, 246, 0.08));
|
||||
border-top: 1px solid rgba(214, 241, 255, 0.7);
|
||||
border-bottom: 1px solid rgba(83, 173, 255, 0.48);
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
letter-spacing: 0;
|
||||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.85), 0 0 12px rgba(57, 151, 255, 0.72);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.staff-home-map-wrap {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 30px;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: radial-gradient(circle at center, rgba(181, 223, 255, 0.3), rgba(54, 145, 235, 0.08) 56%, rgba(54, 145, 235, 0));
|
||||
}
|
||||
|
||||
.staff-home-map {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -40px;
|
||||
top: -100px;
|
||||
width: calc(100% + 100px);
|
||||
height: calc(100% + 100px);
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
object-fit: fill;
|
||||
filter: drop-shadow(0 0 18px rgba(91, 177, 255, 0.52));
|
||||
}
|
||||
|
||||
.fullscreen-btn {
|
||||
position: fixed;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
z-index: 20;
|
||||
height: 34px;
|
||||
min-width: 86px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid rgba(220, 246, 255, 0.72);
|
||||
border-radius: 4px;
|
||||
background: rgba(20, 101, 188, 0.58);
|
||||
color: #f4fbff;
|
||||
font-size: 13px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 14px rgba(64, 161, 255, 0.35);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.fullscreen-btn:hover {
|
||||
background: rgba(20, 126, 220, 0.72);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" class="dashboard-wrap" v-cloak>
|
||||
<main class="dashboard-stage">
|
||||
<section class="staff-home-panel">
|
||||
<div class="staff-home-title">职工小家</div>
|
||||
<div class="staff-home-map-wrap">
|
||||
<img class="staff-home-map" src="${base!}/assets/platform/images/careData/leader/staff-home-campus-map.png?v=20260527" alt="">
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<button class="fullscreen-btn" type="button" @click="toggleFullscreen">{{ fullscreen ? "\u9000\u51fa\u5168\u5c4f" : "\u5168\u5c4f\u663e\u793a" }}</button>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
fullscreen: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.addEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("fullscreenchange", this.syncFullscreenState)
|
||||
document.removeEventListener("webkitfullscreenchange", this.syncFullscreenState)
|
||||
},
|
||||
methods: {
|
||||
toggleFullscreen() {
|
||||
if (this.fullscreen) {
|
||||
const exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen
|
||||
exitFullscreen && exitFullscreen.call(document)
|
||||
return
|
||||
}
|
||||
const target = document.documentElement
|
||||
const requestFullscreen = target.requestFullscreen || target.webkitRequestFullscreen
|
||||
if (requestFullscreen) {
|
||||
const result = requestFullscreen.call(target)
|
||||
if (result && result.catch) {
|
||||
result.catch(() => {})
|
||||
}
|
||||
}
|
||||
},
|
||||
syncFullscreenState() {
|
||||
this.fullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -202,12 +202,22 @@ layout("/layouts/platform.html"){
|
||||
<el-form-item label="获奖材料">{{ viewData.awardMaterialsExcel }}</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<table-tool title="荣誉照片"></table-tool>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="照片">
|
||||
<file-preview v-if="viewData.photoFiles&&viewData.photoFiles.length" :files="viewData.photoFiles"
|
||||
complete_result></file-preview>
|
||||
<span v-else>暂无</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<table-tool title="附件"></table-tool>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="user_name" label="附  件">
|
||||
<file-upload v-if="viewData.files&&viewData.files.length" :files="viewData.files"
|
||||
:view="true"></file-upload>
|
||||
<el-form-item prop="user_name" label="附件">
|
||||
<file-preview v-if="viewData.files&&viewData.files.length" :files="viewData.files"
|
||||
complete_result></file-preview>
|
||||
<span v-else>暂无</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -241,7 +251,7 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"file-upload": httpVueLoader("/components/plugins/FileUpload.vue")
|
||||
"file-preview": httpVueLoader("/components/plugins/sysFilePreview/index.vue")
|
||||
},
|
||||
methods: {
|
||||
dropdownCommand(command) {
|
||||
@@ -255,12 +265,29 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
openView(row) {
|
||||
if (row.files) {
|
||||
row.files = JSON.parse(row.files)
|
||||
}
|
||||
this.viewData = row
|
||||
const viewRow = Object.assign({}, row)
|
||||
viewRow.files = this.parseJsonArray(viewRow.files)
|
||||
viewRow.photoFiles = this.parseJsonArray(viewRow.photoFiles)
|
||||
this.viewData = viewRow
|
||||
this.$refs.guava.view()
|
||||
},
|
||||
parseJsonArray(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
}
|
||||
if (!value) {
|
||||
return []
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return Array.isArray(parsed) ? parsed : []
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
return []
|
||||
},
|
||||
doExport() {
|
||||
if(!this.pageForm.honorType) {
|
||||
this.$message.warning("请选择荣誉类型")
|
||||
@@ -307,42 +334,45 @@ layout("/layouts/platform.html"){
|
||||
const res = await this.$axios.post("/platform/honor/basic/settings/getData", {parentId: honorType})
|
||||
return res.data
|
||||
},
|
||||
getHonorType() {
|
||||
this.$axios.post("/platform/honor/basic/settings/getHonorType").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.honorTypeList = res.data
|
||||
console.log(this.honorTypeList)
|
||||
}
|
||||
})
|
||||
async getHonorType() {
|
||||
const res = await this.$axios.post("/platform/honor/basic/settings/getHonorType")
|
||||
if (res.code === 0) {
|
||||
this.honorTypeList = res.data
|
||||
}
|
||||
},
|
||||
getHonorLevel() {
|
||||
this.$axios.post("/platform/honor/basic/settings/getHonorLevel").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.honorLevelList = res.data
|
||||
}
|
||||
})
|
||||
async getHonorLevel() {
|
||||
const res = await this.$axios.post("/platform/honor/basic/settings/getHonorLevel")
|
||||
if (res.code === 0) {
|
||||
this.honorLevelList = res.data
|
||||
}
|
||||
},
|
||||
getHonorAwardType() {
|
||||
this.$axios.post("/platform/honor/basic/settings/getHonorAwardType").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.honorAwardList = res.data
|
||||
}
|
||||
})
|
||||
async getHonorAwardType() {
|
||||
const res = await this.$axios.post("/platform/honor/basic/settings/getHonorAwardType")
|
||||
if (res.code === 0) {
|
||||
this.honorAwardList = res.data
|
||||
}
|
||||
},
|
||||
getDefaultHonorType() {
|
||||
if (!this.honorTypeList || this.honorTypeList.length === 0) {
|
||||
return null
|
||||
}
|
||||
return this.honorTypeList.find((item) => item.queryTypeCode === "HONOR_SINGLE")
|
||||
|| this.honorTypeList.find((item) => item.name === "个人荣誉")
|
||||
|| this.honorTypeList[0]
|
||||
},
|
||||
async initData() {
|
||||
this.getHonorType()
|
||||
this.getHonorLevel()
|
||||
this.getHonorAwardType()
|
||||
await this.getHonorType()
|
||||
await this.getHonorLevel()
|
||||
await this.getHonorAwardType()
|
||||
this.$businessTool.listUnit().then((data) => {
|
||||
this.units = data
|
||||
})
|
||||
this.unionList = await this.$businessTool.listUnion()
|
||||
if (this.honorTypeList && this.honorLevelList.length > 0) {
|
||||
this.formData = {
|
||||
honorType: this.honorTypeList[0].id,
|
||||
queryTypeCode: this.honorLevelList[0].queryTypeCode
|
||||
}
|
||||
this.honorPrizeList = await this.getHonorPrize(this.formData.honorType)
|
||||
const defaultHonorType = this.getDefaultHonorType()
|
||||
if (defaultHonorType) {
|
||||
this.$set(this.pageForm, "honorType", defaultHonorType.id)
|
||||
this.$set(this.pageForm, "queryTypeCode", defaultHonorType.queryTypeCode)
|
||||
this.honorPrizeList = await this.getHonorPrize(defaultHonorType.id)
|
||||
}
|
||||
},
|
||||
async honorTypeChange(val) {
|
||||
@@ -352,10 +382,18 @@ layout("/layouts/platform.html"){
|
||||
this.$set(this.pageForm, "queryTypeCode", data.queryTypeCode)
|
||||
}
|
||||
this.doSearch()
|
||||
},
|
||||
consumeRegistrationRefreshFlag() {
|
||||
if (sessionStorage.getItem("honorManageNeedRefresh") === "1") {
|
||||
sessionStorage.removeItem("honorManageNeedRefresh")
|
||||
this.tableKey = Date.now()
|
||||
this.pageForm.pageNumber = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.initData()
|
||||
this.consumeRegistrationRefreshFlag()
|
||||
await this.pageData()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -267,10 +267,27 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-col>-->
|
||||
</el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="荣誉照片" prop="photoFiles">
|
||||
<file-upload
|
||||
:value.sync="formData.photoFiles"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
upload_mode="drag"
|
||||
:upload_number="10"
|
||||
upload_result_category="array"
|
||||
complete_result
|
||||
:upload_size="50 * 1024 * 1024"></file-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="附件" prop="files">
|
||||
<file-upload card :files.sync="formData.files"
|
||||
:max-size="50 * 1024 * 1024"></file-upload>
|
||||
<file-upload
|
||||
:value.sync="formData.files"
|
||||
upload_mode="drag"
|
||||
:upload_number="10"
|
||||
upload_result_category="array"
|
||||
complete_result
|
||||
:upload_size="50 * 1024 * 1024"></file-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
@@ -279,7 +296,7 @@ layout("/layouts/platform.html"){
|
||||
</el-form>
|
||||
<el-row class="m20" style="text-align: right">
|
||||
<el-button v-if="this.id" @click="doBack">返回</el-button>
|
||||
<el-button type="primary" @click="doSubmit">提交</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="doSubmit">提交</el-button>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</guava>
|
||||
@@ -321,17 +338,26 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
doSubmit() {
|
||||
this.formData.awardMaterials = JSON.stringify(this.formData.awardMaterials)
|
||||
this.formData.files = JSON.stringify(this.formData.files)
|
||||
this.$axios.post("/platform/honor/registration/doSubmit", this.formData).then((res) => {
|
||||
if (this.submitLoading) {
|
||||
return
|
||||
}
|
||||
this.submitLoading = true
|
||||
const submitData = Object.assign({}, this.formData, {
|
||||
awardMaterials: JSON.stringify(this.formData.awardMaterials || []),
|
||||
files: JSON.stringify(this.formData.files || []),
|
||||
photoFiles: JSON.stringify(this.formData.photoFiles || [])
|
||||
})
|
||||
this.$axios.post("/platform/honor/registration/doSubmit", submitData).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("操作成功,即将跳转至台账界面")
|
||||
setTimeout(() => {
|
||||
pjaxReplace("/platform/honor/manage")
|
||||
}, 500)
|
||||
this.$message.success("操作成功")
|
||||
sessionStorage.setItem("honorManageNeedRefresh", "1")
|
||||
pjaxReplace("/platform/honor/manage?refresh=" + Date.now())
|
||||
} else {
|
||||
this.submitLoading = false
|
||||
this.$message.error(res.msg)
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitLoading = false
|
||||
})
|
||||
},
|
||||
userChange(id) {
|
||||
@@ -403,10 +429,30 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
normalizeJsonArray(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
}
|
||||
if (!value) {
|
||||
return []
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return Array.isArray(parsed) ? parsed : []
|
||||
} catch (e) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
return []
|
||||
},
|
||||
async findData(id) {
|
||||
const resp = await this.$axios.post(loc() + "/findData", {id: id})
|
||||
const data1 = resp.data
|
||||
this.formData = resp.data
|
||||
this.$set(this.formData, "awardMaterials", this.normalizeJsonArray(this.formData.awardMaterials))
|
||||
this.$set(this.formData, "files", this.normalizeJsonArray(this.formData.files))
|
||||
this.$set(this.formData, "photoFiles", this.normalizeJsonArray(this.formData.photoFiles))
|
||||
if (this.formData.userId && this.formData.userId !== "") {
|
||||
await this.userRemoteMethod(this.formData.userName)
|
||||
} else {
|
||||
@@ -441,7 +487,10 @@ layout("/layouts/platform.html"){
|
||||
if (this.honorTypeList && this.honorTypeList.length > 0) {
|
||||
this.formData = {
|
||||
honorType: this.honorTypeList[0].id,
|
||||
queryTypeCode: this.honorTypeList[0].queryTypeCode
|
||||
queryTypeCode: this.honorTypeList[0].queryTypeCode,
|
||||
awardMaterials: [],
|
||||
files: [],
|
||||
photoFiles: []
|
||||
}
|
||||
this.honorPrizeList = await this.getHonorPrize(this.formData.honorType)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,494 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="honor-showcase">
|
||||
<van-nav-bar
|
||||
title="劳模先进"
|
||||
left-text="返回"
|
||||
left-arrow
|
||||
fixed
|
||||
placeholder
|
||||
@click-left="goBack"
|
||||
></van-nav-bar>
|
||||
|
||||
<div class="honor-tabs">
|
||||
<button
|
||||
type="button"
|
||||
class="honor-tab"
|
||||
:class="{ active: activeTab === 'labor' }"
|
||||
@click="switchTab('labor')">
|
||||
劳模风采
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="honor-tab"
|
||||
:class="{ active: activeTab === 'studio' }"
|
||||
@click="switchTab('studio')">
|
||||
创新工作室
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<section class="honor-intro">
|
||||
<div class="honor-intro__corner honor-intro__corner--left"></div>
|
||||
<div class="honor-intro__corner honor-intro__corner--right"></div>
|
||||
<p>一份坚守,淬炼出奋斗的生命价值;一份专注,迸发不断创新的发展动力。</p>
|
||||
<p>他们扎根岗位、追求卓越,以实干书写担当,用匠心点亮前行方向。</p>
|
||||
<p>致敬劳模先进,礼赞奋斗精神。</p>
|
||||
</section>
|
||||
|
||||
<van-loading v-if="loading" class="honor-loading" color="#fff">加载中...</van-loading>
|
||||
|
||||
<div v-else class="honor-list">
|
||||
<article v-for="item in honorList" :key="item.id" class="honor-card">
|
||||
<div class="honor-card__image-wrap">
|
||||
<img v-if="item.cover" class="honor-card__image" :src="item.cover" alt="">
|
||||
<div v-else class="honor-card__placeholder">
|
||||
<div class="honor-card__placeholder-title">{{ getDisplayName(item) }}</div>
|
||||
<div class="honor-card__placeholder-sub">劳模先进</div>
|
||||
</div>
|
||||
<div class="honor-card__name">{{ getDisplayName(item) }}</div>
|
||||
</div>
|
||||
<div class="honor-card__body">
|
||||
<div class="honor-card__gold-line"></div>
|
||||
<div class="honor-card__prize">《{{ item.prizeName || '荣誉奖项' }}》</div>
|
||||
<div class="honor-card__date" v-if="item.grantDate">授予时间:{{ item.grantDate }}</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<van-empty v-if="honorList.length === 0" image="search" description="暂无当年荣誉"></van-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: function () {
|
||||
return {
|
||||
activeTab: "labor",
|
||||
currentYear: new Date().getFullYear(),
|
||||
honorTypeList: [],
|
||||
honorTypeMap: {
|
||||
labor: null,
|
||||
studio: null
|
||||
},
|
||||
honorList: [],
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack: function () {
|
||||
this.returnHome()
|
||||
},
|
||||
returnHome: function () {
|
||||
if (window.store && typeof window.store.commit === "function") {
|
||||
window.store.commit("setActiveTarBar", "home")
|
||||
}
|
||||
if (!window.$ || !$.support || !$.support.pjax) {
|
||||
window.location.replace("/platform/h5/home")
|
||||
return
|
||||
}
|
||||
var fallbackTimer = window.setTimeout(function () {
|
||||
window.location.replace("/platform/h5/home")
|
||||
}, 1200)
|
||||
$(document).one("pjax:complete", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
})
|
||||
$(document).one("pjax:error pjax:timeout", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
window.location.replace("/platform/h5/home")
|
||||
})
|
||||
$.pjax({
|
||||
url: "/platform/h5/home",
|
||||
container: "#container",
|
||||
fragment: "#container",
|
||||
push: false,
|
||||
replace: true,
|
||||
timeout: 8000
|
||||
})
|
||||
},
|
||||
switchTab: function (tab) {
|
||||
if (this.activeTab === tab) {
|
||||
return
|
||||
}
|
||||
this.activeTab = tab
|
||||
this.listHonor()
|
||||
},
|
||||
getDisplayName: function (item) {
|
||||
if (this.activeTab === "studio") {
|
||||
return item.applyUnionName || item.unionName || item.userName || "创新工作室"
|
||||
}
|
||||
return item.userName || item.applyUnionName || item.unionName || "劳模先进"
|
||||
},
|
||||
getHonorTypes: function () {
|
||||
var self = this
|
||||
return this.$axios.post("/platform/honor/basic/settings/getHonorType").then(function (res) {
|
||||
if (res.code === 0) {
|
||||
self.honorTypeList = res.data || []
|
||||
self.honorTypeMap.labor = self.findHonorType("HONOR_SINGLE", "个人荣誉")
|
||||
self.honorTypeMap.studio = self.findHonorType("HONOR_LIST", "集体荣誉")
|
||||
}
|
||||
})
|
||||
},
|
||||
findHonorType: function (queryTypeCode, name) {
|
||||
var target = this.honorTypeList.find(function (item) {
|
||||
return item.queryTypeCode === queryTypeCode
|
||||
})
|
||||
if (!target) {
|
||||
target = this.honorTypeList.find(function (item) {
|
||||
return item.name === name
|
||||
})
|
||||
}
|
||||
return target || null
|
||||
},
|
||||
listHonor: function () {
|
||||
var self = this
|
||||
var type = this.activeTab === "studio" ? this.honorTypeMap.studio : this.honorTypeMap.labor
|
||||
if (!type) {
|
||||
this.honorList = []
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
this.$axios.post("/platform/honor/manage/h5Data", {
|
||||
year: this.currentYear,
|
||||
honorType: type.id,
|
||||
pageNumber: 1,
|
||||
pageSize: 50
|
||||
}).then(function (res) {
|
||||
if (res.code === 0) {
|
||||
var list = (res.data && res.data.list) || []
|
||||
self.honorList = list.map(function (item) {
|
||||
item.cover = ""
|
||||
item.photoId = self.getFirstPhotoId(item.photoFiles)
|
||||
return item
|
||||
})
|
||||
self.loadPhotoMap()
|
||||
} else {
|
||||
self.honorList = []
|
||||
}
|
||||
}).finally(function () {
|
||||
self.loading = false
|
||||
})
|
||||
},
|
||||
getFirstPhotoId: function (photoFiles) {
|
||||
var files = []
|
||||
if (Array.isArray(photoFiles)) {
|
||||
files = photoFiles
|
||||
} else if (photoFiles) {
|
||||
try {
|
||||
files = JSON.parse(photoFiles)
|
||||
} catch (e) {
|
||||
files = []
|
||||
}
|
||||
}
|
||||
if (!files.length) {
|
||||
return ""
|
||||
}
|
||||
var first = files[0]
|
||||
var data = first && first.response ? first.response.data : first
|
||||
if (!data) {
|
||||
return ""
|
||||
}
|
||||
data = String(data)
|
||||
return data.indexOf("=") > -1 ? data.substring(data.lastIndexOf("=") + 1) : data
|
||||
},
|
||||
loadPhotoMap: function () {
|
||||
var self = this
|
||||
var ids = this.honorList.map(function (item) {
|
||||
return item.photoId
|
||||
}).filter(function (id) {
|
||||
return !!id
|
||||
})
|
||||
if (!ids.length) {
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/sys/file/previewFileData", { ids: JSON.stringify(ids) }).then(function (res) {
|
||||
if (res.code !== 0) {
|
||||
return
|
||||
}
|
||||
var fileMap = {}
|
||||
;(res.data || []).forEach(function (file) {
|
||||
fileMap[file.id] = file.thumbnail || file.downloadPath || ""
|
||||
})
|
||||
self.honorList = self.honorList.map(function (item) {
|
||||
item.cover = fileMap[item.photoId] || ""
|
||||
return item
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
var self = this
|
||||
this.getHonorTypes().then(function () {
|
||||
self.listHonor()
|
||||
})
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
body {
|
||||
background: #c80019;
|
||||
}
|
||||
|
||||
.honor-showcase {
|
||||
min-height: 100vh;
|
||||
padding: 0 14px 28px;
|
||||
box-sizing: border-box;
|
||||
background:
|
||||
radial-gradient(circle at 50% 0, rgba(255, 113, 89, .42) 0, rgba(255, 113, 89, 0) 32%),
|
||||
linear-gradient(180deg, #d6001c 0%, #bd0018 56%, #a90016 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-nav-bar {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-nav-bar__title {
|
||||
color: #20242a;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-nav-bar .van-icon,
|
||||
.honor-showcase /deep/ .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-hairline--bottom::after {
|
||||
border-color: #eef1f6;
|
||||
}
|
||||
|
||||
.honor-tabs {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 76px;
|
||||
}
|
||||
|
||||
.honor-tab {
|
||||
position: relative;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: rgba(255, 247, 220, .76);
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
line-height: 28px;
|
||||
padding: 0 8px 14px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.honor-tab.active {
|
||||
color: #fff6d9;
|
||||
}
|
||||
|
||||
.honor-tab.active::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 4px;
|
||||
width: 38px;
|
||||
height: 5px;
|
||||
border-radius: 999px;
|
||||
background: #ffe6a3;
|
||||
transform: translateX(-50%);
|
||||
box-shadow: 0 2px 8px rgba(255, 230, 163, .38);
|
||||
}
|
||||
|
||||
.honor-intro {
|
||||
position: relative;
|
||||
margin-bottom: 18px;
|
||||
padding: 20px 20px 46px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
color: #ffe9bd;
|
||||
background:
|
||||
linear-gradient(165deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0) 46%),
|
||||
linear-gradient(180deg, #d73535 0%, #c9262f 100%);
|
||||
box-shadow: 0 10px 22px rgba(90, 0, 8, .22);
|
||||
}
|
||||
|
||||
.honor-intro::before,
|
||||
.honor-intro::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -30px;
|
||||
right: -30px;
|
||||
height: 58px;
|
||||
border: 5px solid rgba(255, 223, 151, .86);
|
||||
border-top: 0;
|
||||
border-radius: 0 0 50% 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.honor-intro::before {
|
||||
bottom: 14px;
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
.honor-intro::after {
|
||||
bottom: -12px;
|
||||
opacity: .75;
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
|
||||
.honor-intro p {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin: 0 0 9px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.honor-intro p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.honor-intro__corner {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-top: 3px solid rgba(255, 224, 161, .82);
|
||||
}
|
||||
|
||||
.honor-intro__corner--left {
|
||||
left: 14px;
|
||||
border-left: 3px solid rgba(255, 224, 161, .82);
|
||||
}
|
||||
|
||||
.honor-intro__corner--right {
|
||||
right: 14px;
|
||||
border-right: 3px solid rgba(255, 224, 161, .82);
|
||||
}
|
||||
|
||||
.honor-loading {
|
||||
margin-top: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.honor-list {
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.honor-card {
|
||||
margin-bottom: 18px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #be0018;
|
||||
box-shadow: 0 10px 22px rgba(83, 0, 9, .28);
|
||||
}
|
||||
|
||||
.honor-card__image-wrap {
|
||||
position: relative;
|
||||
height: 206px;
|
||||
overflow: hidden;
|
||||
background: #e6b06d;
|
||||
}
|
||||
|
||||
.honor-card__image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.honor-card__placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff5d8;
|
||||
background:
|
||||
radial-gradient(circle at 78% 30%, rgba(255, 221, 148, .36), rgba(255, 221, 148, 0) 26%),
|
||||
linear-gradient(140deg, #d93a31 0%, #b60018 100%);
|
||||
}
|
||||
|
||||
.honor-card__placeholder-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.honor-card__placeholder-sub {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0;
|
||||
color: rgba(255, 245, 216, .82);
|
||||
}
|
||||
|
||||
.honor-card__image-wrap::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 58px;
|
||||
background: linear-gradient(165deg, rgba(177, 0, 24, .86) 0%, rgba(177, 0, 24, .74) 62%, rgba(177, 0, 24, .1) 63%);
|
||||
}
|
||||
|
||||
.honor-card__name {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
bottom: 16px;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
line-height: 28px;
|
||||
font-weight: 800;
|
||||
text-shadow: 0 2px 8px rgba(89, 0, 12, .32);
|
||||
}
|
||||
|
||||
.honor-card__body {
|
||||
position: relative;
|
||||
min-height: 82px;
|
||||
padding: 22px 20px 20px;
|
||||
box-sizing: border-box;
|
||||
color: #ffe5ad;
|
||||
background:
|
||||
radial-gradient(circle at 92% 14%, rgba(255, 230, 168, .4), rgba(255, 230, 168, 0) 16%),
|
||||
#be0018;
|
||||
}
|
||||
|
||||
.honor-card__body::after {
|
||||
content: "★";
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
top: -20px;
|
||||
color: #ffd886;
|
||||
font-size: 42px;
|
||||
text-shadow: 0 3px 8px rgba(85, 0, 9, .28);
|
||||
transform: rotate(-12deg);
|
||||
}
|
||||
|
||||
.honor-card__gold-line {
|
||||
width: 44px;
|
||||
height: 3px;
|
||||
border-radius: 999px;
|
||||
background: #e7b13c;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.honor-card__prize {
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 700;
|
||||
color: #ffe5ad;
|
||||
}
|
||||
|
||||
.honor-card__date {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: rgba(255, 229, 173, .72);
|
||||
}
|
||||
|
||||
.honor-showcase /deep/ .van-empty__description {
|
||||
color: rgba(255, 255, 255, .78);
|
||||
}
|
||||
`
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
layout("/layouts/platform_tour_signup_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
@@ -274,6 +274,20 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatDateTime(date) {
|
||||
const pad = (value) => String(value).padStart(2, "0")
|
||||
return date.getFullYear()
|
||||
+ "-"
|
||||
+ pad(date.getMonth() + 1)
|
||||
+ "-"
|
||||
+ pad(date.getDate())
|
||||
+ " "
|
||||
+ pad(date.getHours())
|
||||
+ ":"
|
||||
+ pad(date.getMinutes())
|
||||
+ ":"
|
||||
+ pad(date.getSeconds())
|
||||
},
|
||||
init() {
|
||||
if (!this.matterId) {
|
||||
vant.Dialog.alert({ title: "提示", message: "报名事项参数缺失", confirmButtonColor: "#1867b0" })
|
||||
@@ -326,7 +340,7 @@ layout("/layouts/platform_h5.html"){
|
||||
unitName: "",
|
||||
unionId: "",
|
||||
unionName: "",
|
||||
signupTime: this.$moment ? this.$moment().format("YYYY-MM-DD HH:mm:ss") : "",
|
||||
signupTime: this.formatDateTime(new Date()),
|
||||
matterId: matter.matterId || "",
|
||||
lineId: matter.lineId || "",
|
||||
lineName: matter.lineName || "",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
layout("/layouts/platform_tour_signup_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
@@ -104,10 +104,41 @@ layout("/layouts/platform_h5.html"){
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.tour-signup-notice /deep/ #pdf-container {
|
||||
.tour-pdf-preview {
|
||||
min-height: 560px;
|
||||
}
|
||||
|
||||
.tour-pdf-status {
|
||||
padding: 16px 0;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tour-pdf-toolbar {
|
||||
margin-bottom: 8px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.tour-pdf-pages {
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.tour-pdf-page {
|
||||
margin-bottom: 10px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #f8fafc;
|
||||
box-shadow: 0 1px 4px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.tour-pdf-page canvas {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tour-signup-empty {
|
||||
padding: 34px 0 26px;
|
||||
}
|
||||
@@ -146,7 +177,20 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
<van-skeleton title :row="8" :loading="loading">
|
||||
<div v-if="setting.serviceNotice" class="tour-signup-notice">
|
||||
<pdf-preview :key="serviceNoticeKey" :content="setting.serviceNotice"></pdf-preview>
|
||||
<div v-if="serviceNoticePdfHref" class="tour-pdf-preview">
|
||||
<div v-if="pdfPageCount" class="tour-pdf-toolbar">
|
||||
已加载 {{ pdfRenderedPages }} / {{ pdfPageCount }} 页
|
||||
</div>
|
||||
<div ref="pdfPreviewContainer" class="tour-pdf-pages"></div>
|
||||
<div v-if="pdfLoading && pdfRenderedPages === 0" class="tour-pdf-status">
|
||||
<van-loading size="22px" vertical>正在加载第一页...</van-loading>
|
||||
</div>
|
||||
<div v-else-if="pdfLoading" class="tour-pdf-status">
|
||||
正在继续加载后续页面...
|
||||
</div>
|
||||
<div v-if="pdfError" class="tour-pdf-status">{{ pdfError }}</div>
|
||||
</div>
|
||||
<div v-else v-html="setting.serviceNotice"></div>
|
||||
</div>
|
||||
<van-empty v-else class="tour-signup-empty" description="暂无服务须知"></van-empty>
|
||||
</van-skeleton>
|
||||
@@ -161,14 +205,18 @@ layout("/layouts/platform_h5.html"){
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
currentYear: new Date().getFullYear(),
|
||||
serviceNoticeKey: "",
|
||||
serviceNoticePdfHref: "",
|
||||
pdfDoc: null,
|
||||
pdfLoadingTask: null,
|
||||
pdfLoading: false,
|
||||
pdfError: "",
|
||||
pdfPageCount: 0,
|
||||
pdfRenderedPages: 0,
|
||||
pdfRenderToken: 0,
|
||||
bannerList: [
|
||||
"/assets/platform/images/tour/tour-h5-banner-1.jpg",
|
||||
"/assets/platform/images/tour/tour-h5-banner-2.jpg"
|
||||
@@ -181,13 +229,155 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
parseContentHref(content) {
|
||||
if (!content) {
|
||||
return ""
|
||||
}
|
||||
try {
|
||||
const parser = new DOMParser()
|
||||
const doc = parser.parseFromString(content, "text/html")
|
||||
const link = doc.querySelector("a[href]")
|
||||
return link ? link.getAttribute("href") : ""
|
||||
} catch (e) {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
getPdfLib() {
|
||||
return window.pdfjsLib || window["pdfjs-dist/build/pdf"]
|
||||
},
|
||||
loadPdfLib() {
|
||||
const pdfLib = this.getPdfLib()
|
||||
if (pdfLib && pdfLib.getDocument) {
|
||||
return Promise.resolve(pdfLib)
|
||||
}
|
||||
return window.loadScriptOnce("/assets/platform/plugins/pdfJs/h5/pdf.js?v=20260524").then(() => {
|
||||
const loadedPdfLib = this.getPdfLib()
|
||||
if (!loadedPdfLib || !loadedPdfLib.getDocument) {
|
||||
throw new Error("pdf lib load failed")
|
||||
}
|
||||
return loadedPdfLib
|
||||
})
|
||||
},
|
||||
clearPdfPreview() {
|
||||
this.pdfRenderToken += 1
|
||||
this.pdfDoc = null
|
||||
this.pdfLoading = false
|
||||
this.pdfError = ""
|
||||
this.pdfPageCount = 0
|
||||
this.pdfRenderedPages = 0
|
||||
if (this.pdfLoadingTask && this.pdfLoadingTask.destroy) {
|
||||
try {
|
||||
this.pdfLoadingTask.destroy()
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
this.pdfLoadingTask = null
|
||||
if (this.$refs.pdfPreviewContainer) {
|
||||
this.$refs.pdfPreviewContainer.innerHTML = ""
|
||||
}
|
||||
},
|
||||
renderServiceNoticePdf() {
|
||||
this.clearPdfPreview()
|
||||
if (!this.serviceNoticePdfHref) {
|
||||
return
|
||||
}
|
||||
const token = this.pdfRenderToken
|
||||
this.pdfLoading = true
|
||||
this.loadPdfLib().then((pdfLib) => {
|
||||
if (token !== this.pdfRenderToken) {
|
||||
return null
|
||||
}
|
||||
if (pdfLib.GlobalWorkerOptions) {
|
||||
pdfLib.GlobalWorkerOptions.workerSrc = "/assets/platform/plugins/pdfJs/h5/pdf.worker.js?v=20260524"
|
||||
}
|
||||
this.pdfLoadingTask = pdfLib.getDocument({
|
||||
url: this.serviceNoticePdfHref,
|
||||
disableAutoFetch: false,
|
||||
disableStream: false,
|
||||
disableRange: false
|
||||
})
|
||||
return this.pdfLoadingTask.promise
|
||||
}).then((pdf) => {
|
||||
if (token !== this.pdfRenderToken || !pdf) {
|
||||
return
|
||||
}
|
||||
this.pdfDoc = pdf
|
||||
this.pdfPageCount = pdf.numPages || 0
|
||||
return this.renderPdfPage(1, token)
|
||||
}).then(() => {
|
||||
if (token !== this.pdfRenderToken) {
|
||||
return
|
||||
}
|
||||
this.renderRestPdfPages(2, token)
|
||||
}).catch(() => {
|
||||
if (token !== this.pdfRenderToken) {
|
||||
return
|
||||
}
|
||||
this.pdfLoading = false
|
||||
this.pdfError = "PDF加载失败,请稍后重试"
|
||||
})
|
||||
},
|
||||
renderPdfPage(pageNumber, token) {
|
||||
if (!this.pdfDoc || token !== this.pdfRenderToken || pageNumber > this.pdfPageCount) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
return this.pdfDoc.getPage(pageNumber).then((page) => {
|
||||
if (token !== this.pdfRenderToken || !this.$refs.pdfPreviewContainer) {
|
||||
return
|
||||
}
|
||||
const container = this.$refs.pdfPreviewContainer
|
||||
const baseViewport = page.getViewport({scale: 1})
|
||||
const containerWidth = Math.max(container.clientWidth || 0, window.innerWidth - 44)
|
||||
const cssScale = containerWidth / baseViewport.width
|
||||
const outputScale = Math.min(window.devicePixelRatio || 1, 2)
|
||||
const viewport = page.getViewport({scale: cssScale})
|
||||
const pageEl = document.createElement("div")
|
||||
pageEl.className = "tour-pdf-page"
|
||||
const canvas = document.createElement("canvas")
|
||||
const context = canvas.getContext("2d")
|
||||
canvas.width = Math.floor(viewport.width * outputScale)
|
||||
canvas.height = Math.floor(viewport.height * outputScale)
|
||||
canvas.style.width = Math.floor(viewport.width) + "px"
|
||||
canvas.style.height = Math.floor(viewport.height) + "px"
|
||||
pageEl.appendChild(canvas)
|
||||
container.appendChild(pageEl)
|
||||
return page.render({
|
||||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
transform: outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null
|
||||
}).promise.then(() => {
|
||||
if (token === this.pdfRenderToken) {
|
||||
this.pdfRenderedPages = Math.max(this.pdfRenderedPages, pageNumber)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
renderRestPdfPages(pageNumber, token) {
|
||||
if (token !== this.pdfRenderToken || !this.pdfDoc || pageNumber > this.pdfPageCount) {
|
||||
this.pdfLoading = false
|
||||
return
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.renderPdfPage(pageNumber, token).then(() => {
|
||||
this.renderRestPdfPages(pageNumber + 1, token)
|
||||
}).catch(() => {
|
||||
if (token === this.pdfRenderToken) {
|
||||
this.pdfLoading = false
|
||||
this.pdfError = "部分页面加载失败"
|
||||
}
|
||||
})
|
||||
}, 120)
|
||||
},
|
||||
loadServiceNotice() {
|
||||
this.loading = true
|
||||
this.$axios.post("/platform/tour/signup/h5/serviceNotice").then((res) => {
|
||||
this.loading = false
|
||||
if (res.code === 0) {
|
||||
this.setting = Object.assign({}, this.setting, res.data || {})
|
||||
this.serviceNoticeKey = (this.setting.year || this.currentYear) + "_" + new Date().getTime()
|
||||
this.serviceNoticePdfHref = this.parseContentHref(this.setting.serviceNotice)
|
||||
this.$nextTick(() => {
|
||||
this.renderServiceNoticePdf()
|
||||
})
|
||||
} else {
|
||||
vant.Toast(res.msg || "服务须知加载失败")
|
||||
}
|
||||
@@ -201,6 +391,9 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
created() {
|
||||
this.loadServiceNotice()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearPdfPreview()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
layout("/layouts/platform_tour_signup_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
@@ -340,6 +340,19 @@ layout("/layouts/platform_h5.html"){
|
||||
getPdfLib() {
|
||||
return window.pdfjsLib || window["pdfjs-dist/build/pdf"]
|
||||
},
|
||||
loadPdfLib() {
|
||||
const pdfLib = this.getPdfLib()
|
||||
if (pdfLib && pdfLib.getDocument) {
|
||||
return Promise.resolve(pdfLib)
|
||||
}
|
||||
return window.loadScriptOnce("/assets/platform/plugins/pdfJs/h5/pdf.js?v=20260524").then(() => {
|
||||
const loadedPdfLib = this.getPdfLib()
|
||||
if (!loadedPdfLib || !loadedPdfLib.getDocument) {
|
||||
throw new Error("pdf lib load failed")
|
||||
}
|
||||
return loadedPdfLib
|
||||
})
|
||||
},
|
||||
clearPdfPreview() {
|
||||
this.pdfRenderToken += 1
|
||||
this.pdfDoc = null
|
||||
@@ -363,13 +376,28 @@ layout("/layouts/platform_h5.html"){
|
||||
if (!this.lineContentHref) {
|
||||
return
|
||||
}
|
||||
if (!this.getPdfLib() || !this.getPdfLib().getDocument) {
|
||||
const token = this.pdfRenderToken
|
||||
this.pdfLoading = true
|
||||
this.loadPdfLib().then(() => {
|
||||
if (token === this.pdfRenderToken) {
|
||||
this.renderLinePdf()
|
||||
}
|
||||
}).catch(() => {
|
||||
if (token === this.pdfRenderToken) {
|
||||
this.pdfLoading = false
|
||||
this.pdfError = "PDF预览组件加载失败"
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
const pdfLib = this.getPdfLib()
|
||||
if (!pdfLib || !pdfLib.getDocument) {
|
||||
this.pdfError = "PDF预览组件加载失败"
|
||||
return
|
||||
}
|
||||
if (pdfLib.GlobalWorkerOptions) {
|
||||
pdfLib.GlobalWorkerOptions.workerSrc = "/assets/platform/plugins/pdfJs/h5/pdf.worker.js"
|
||||
pdfLib.GlobalWorkerOptions.workerSrc = "/assets/platform/plugins/pdfJs/h5/pdf.worker.js?v=20260524"
|
||||
}
|
||||
const token = this.pdfRenderToken
|
||||
this.pdfLoading = true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
layout("/layouts/platform_tour_signup_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
@@ -428,7 +428,7 @@ layout("/layouts/platform_h5.html"){
|
||||
class="tour-line-shortcut"
|
||||
:class="{'tour-line-shortcut--active': pageForm.directFamilyUnitLine === true}"
|
||||
@click="toggleDirectFamilyLine">
|
||||
<img class="tour-line-shortcut__icon" src="/assets/platform/images/tour/tour-direct-family.jpg" alt="直系亲属">
|
||||
<img class="tour-line-shortcut__icon" src="/assets/platform/images/tour/tour-direct-family-icon.png?v=20260524" alt="直系亲属">
|
||||
<div class="tour-line-shortcut__text">
|
||||
<div>直系亲属</div>
|
||||
</div>
|
||||
@@ -445,7 +445,14 @@ layout("/layouts/platform_h5.html"){
|
||||
<div class="tour-line-list">
|
||||
<div class="tour-line-card" v-for="row in list" :key="row.matterId" @click="onLine(row)">
|
||||
<div class="tour-line-thumb">
|
||||
<van-image v-if="thumbUrl(row)" :src="thumbUrl(row)" fit="cover"></van-image>
|
||||
<van-image v-if="thumbUrl(row)" :src="thumbUrl(row)" fit="cover" lazy-load>
|
||||
<template #loading>
|
||||
<div class="tour-line-thumb-empty">图片加载中</div>
|
||||
</template>
|
||||
<template #error>
|
||||
<div class="tour-line-thumb-empty">暂无图片</div>
|
||||
</template>
|
||||
</van-image>
|
||||
<div v-else class="tour-line-thumb-empty">暂无图片</div>
|
||||
</div>
|
||||
<div class="tour-line-main">
|
||||
|
||||
@@ -261,7 +261,7 @@ const apps = {
|
||||
return
|
||||
}
|
||||
Promise.all(list.map(app => {
|
||||
return this.$axios.post("/platform/sys/user/subAppMenus", {appId: app.id}).then((res) => {
|
||||
return this.$axios.post("/platform/sys/user/subAppMenus", {appId: app.id, platform: "H5"}).then((res) => {
|
||||
const menus = res.code === 0 ? (res.data || []) : []
|
||||
return {
|
||||
id: app.id,
|
||||
@@ -381,7 +381,7 @@ const apps = {
|
||||
|
||||
// 打开应用
|
||||
openApp(app) {
|
||||
this.$axios.post("/platform/sys/user/subAppMenus", {appId: app.id}).then((res) => {
|
||||
this.$axios.post("/platform/sys/user/subAppMenus", {appId: app.id, platform: "H5"}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.showAppMenus(app, res.data)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="featured-page">
|
||||
<van-nav-bar
|
||||
title="精彩活动"
|
||||
left-text="返回"
|
||||
left-arrow
|
||||
fixed
|
||||
placeholder
|
||||
@click-left="goBack"
|
||||
></van-nav-bar>
|
||||
|
||||
<div class="featured-banner">
|
||||
<img :src="topImage" alt="">
|
||||
<div class="featured-banner__shade"></div>
|
||||
<div class="featured-banner__text">
|
||||
<div class="featured-banner__title">精彩活动</div>
|
||||
<div class="featured-banner__sub">发现更多校园工会活动</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="featured-list">
|
||||
<template v-if="activityOptions && activityOptions.length > 0">
|
||||
<div v-for="item in activityOptions" :key="item.id" class="act-item" @click="enterAct(item)">
|
||||
<van-tag class="act-item-wrapper-tag" v-if="$moment().unix() > $moment(item.endDate).unix()">
|
||||
已结束
|
||||
</van-tag>
|
||||
|
||||
<van-tag class="act-item-wrapper-tag" type="success"
|
||||
v-else-if="$moment().unix() > $moment(item.startDate).unix() && $moment().unix() < $moment(item.endDate).unix()">
|
||||
进行中
|
||||
</van-tag>
|
||||
|
||||
<van-tag class="act-item-wrapper-tag" type="success" v-else-if="$moment().unix() < $moment(item.startDate).unix()">
|
||||
即将开始
|
||||
</van-tag>
|
||||
|
||||
<div class="act-item-cover">
|
||||
<van-image v-if="item.cover" width="120" height="84" :src="item.cover"></van-image>
|
||||
</div>
|
||||
<div class="act-item-wrapper">
|
||||
<div class="content-title">{{ item.name }}</div>
|
||||
<div class="content-text">
|
||||
<div>开始时间:{{ $moment(item.startDate).format('MM-DD HH:mm') }}</div>
|
||||
<div class="mt5">结束时间:{{ $moment(item.endDate).format('MM-DD HH:mm') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<van-empty v-if="!activityOptions || activityOptions.length === 0" description="暂无精彩活动"></van-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: function () {
|
||||
return {
|
||||
topImage: "/assets/mobile/img/home/home1.png",
|
||||
activityOptions: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack: function () {
|
||||
this.returnHome()
|
||||
},
|
||||
returnHome: function () {
|
||||
if (window.store && typeof window.store.commit === "function") {
|
||||
window.store.commit("setActiveTarBar", "home")
|
||||
}
|
||||
if (!window.$ || !$.support || !$.support.pjax) {
|
||||
window.location.replace("/platform/h5/home")
|
||||
return
|
||||
}
|
||||
var fallbackTimer = window.setTimeout(function () {
|
||||
window.location.replace("/platform/h5/home")
|
||||
}, 1200)
|
||||
$(document).one("pjax:complete", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
})
|
||||
$(document).one("pjax:error pjax:timeout", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
window.location.replace("/platform/h5/home")
|
||||
})
|
||||
$.pjax({
|
||||
url: "/platform/h5/home",
|
||||
container: "#container",
|
||||
fragment: "#container",
|
||||
push: false,
|
||||
replace: true,
|
||||
timeout: 8000
|
||||
})
|
||||
},
|
||||
loadTopImage: function () {
|
||||
var self = this
|
||||
this.$axios.post("/open/common/getConfigKey", { key: "AppFeaturedActivityImg" }).then(function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
self.topImage = String(res.data).split(",")[0]
|
||||
}
|
||||
})
|
||||
},
|
||||
listActivity: function () {
|
||||
var self = this
|
||||
this.$axios.post("/platform/home/listHomeActivity").then(function (resp) {
|
||||
if (resp.code === 0) {
|
||||
self.activityOptions = (resp.data || []).filter(function (item) {
|
||||
return !self.isWelfareItem(item)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
isWelfareItem: function (item) {
|
||||
var url = ((item && item.url) || "") + "," + ((item && item.h5Url) || "")
|
||||
return url.indexOf("/welfare/") > -1
|
||||
},
|
||||
enterAct: function (item) {
|
||||
if (this.$moment().unix() < this.$moment(item.startDate).unix()) {
|
||||
this.$toast("活动即将开始")
|
||||
return
|
||||
}
|
||||
this.$pjaxReplace(item.h5Url)
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
this.loadTopImage()
|
||||
this.listActivity()
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
body {
|
||||
background-color: #f4f7fb;
|
||||
}
|
||||
|
||||
.featured-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f4f7fb;
|
||||
padding-bottom: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.featured-page /deep/ .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.featured-page /deep/ .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.featured-page /deep/ .van-nav-bar .van-icon,
|
||||
.featured-page /deep/ .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.featured-banner {
|
||||
position: relative;
|
||||
height: 140px;
|
||||
margin: 12px 12px 10px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background-color: #e9eef6;
|
||||
box-shadow: 0 8px 22px rgba(31, 41, 55, .1);
|
||||
}
|
||||
|
||||
.featured-banner img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.featured-banner__shade {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(90deg, rgba(0, 0, 0, .42), rgba(0, 0, 0, .08));
|
||||
}
|
||||
|
||||
.featured-banner__text {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
bottom: 18px;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, .26);
|
||||
}
|
||||
|
||||
.featured-banner__title {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.featured-banner__sub {
|
||||
margin-top: 5px;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
opacity: .92;
|
||||
}
|
||||
|
||||
.featured-list {
|
||||
margin: 0 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 8px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.act-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 10px 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.act-item + .act-item {
|
||||
border-top: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.featured-list /deep/ .act-item-wrapper-tag {
|
||||
position: absolute !important;
|
||||
top: 10px !important;
|
||||
left: 12px !important;
|
||||
z-index: 2;
|
||||
width: auto !important;
|
||||
min-width: 42px;
|
||||
height: 20px !important;
|
||||
flex: none !important;
|
||||
padding: 0 6px !important;
|
||||
margin: 0 !important;
|
||||
border: 0 !important;
|
||||
border-radius: 2px !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff !important;
|
||||
background-color: #1f73b7 !important;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
white-space: nowrap !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.featured-list /deep/ .act-item-wrapper-tag.van-tag--success {
|
||||
background-color: #1f73b7 !important;
|
||||
}
|
||||
|
||||
.act-item-cover {
|
||||
width: 120px;
|
||||
height: 84px;
|
||||
flex: 0 0 120px;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
background-color: #f2f3f5;
|
||||
}
|
||||
|
||||
.act-item-cover /deep/ .van-image,
|
||||
.act-item-cover /deep/ img {
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: 84px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.act-item-wrapper {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content-title {
|
||||
color: #111827;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
margin-top: 9px;
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.mt5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
`
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,303 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<div class="festival-page">
|
||||
<van-nav-bar
|
||||
title="节日福利"
|
||||
left-text="返回"
|
||||
left-arrow
|
||||
fixed
|
||||
placeholder
|
||||
@click-left="goBack"
|
||||
></van-nav-bar>
|
||||
|
||||
<div class="festival-banner">
|
||||
<img :src="topImage" alt="">
|
||||
<div class="festival-banner__shade"></div>
|
||||
<div class="festival-banner__text">
|
||||
<div class="festival-banner__title">节日福利</div>
|
||||
<div class="festival-banner__sub">查看可参与的节日福利活动</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="festival-list">
|
||||
<template v-if="activityOptions && activityOptions.length > 0">
|
||||
<div v-for="item in activityOptions" :key="item.id" class="act-item" @click="enterAct(item)">
|
||||
<van-tag class="act-item-wrapper-tag" v-if="$moment().unix() > $moment(item.endDate).unix()">
|
||||
已结束
|
||||
</van-tag>
|
||||
|
||||
<van-tag class="act-item-wrapper-tag" type="success"
|
||||
v-else-if="$moment().unix() > $moment(item.startDate).unix() && $moment().unix() < $moment(item.endDate).unix()">
|
||||
进行中
|
||||
</van-tag>
|
||||
|
||||
<van-tag class="act-item-wrapper-tag" type="success" v-else-if="$moment().unix() < $moment(item.startDate).unix()">
|
||||
即将开始
|
||||
</van-tag>
|
||||
|
||||
<div class="act-item-cover">
|
||||
<van-image v-if="item.cover" width="120" height="84" :src="item.cover"></van-image>
|
||||
</div>
|
||||
<div class="act-item-wrapper">
|
||||
<div class="content-title">{{ item.name }}</div>
|
||||
<div class="content-text">
|
||||
<div>开始时间:{{ $moment(item.startDate).format('MM-DD HH:mm') }}</div>
|
||||
<div class="mt5">结束时间:{{ $moment(item.endDate).format('MM-DD HH:mm') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<van-empty v-if="!activityOptions || activityOptions.length === 0" description="暂无节日福利"></van-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: function () {
|
||||
return {
|
||||
topImage: "/assets/mobile/img/home/home2.png",
|
||||
activityOptions: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack: function () {
|
||||
this.returnHome()
|
||||
},
|
||||
returnHome: function () {
|
||||
if (window.store && typeof window.store.commit === "function") {
|
||||
window.store.commit("setActiveTarBar", "home")
|
||||
}
|
||||
if (!window.$ || !$.support || !$.support.pjax) {
|
||||
window.location.replace("/platform/h5/home")
|
||||
return
|
||||
}
|
||||
var fallbackTimer = window.setTimeout(function () {
|
||||
window.location.replace("/platform/h5/home")
|
||||
}, 1200)
|
||||
$(document).one("pjax:complete", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
})
|
||||
$(document).one("pjax:error pjax:timeout", function () {
|
||||
window.clearTimeout(fallbackTimer)
|
||||
window.location.replace("/platform/h5/home")
|
||||
})
|
||||
$.pjax({
|
||||
url: "/platform/h5/home",
|
||||
container: "#container",
|
||||
fragment: "#container",
|
||||
push: false,
|
||||
replace: true,
|
||||
timeout: 8000
|
||||
})
|
||||
},
|
||||
loadTopImage: function () {
|
||||
var self = this
|
||||
this.$axios.post("/open/common/getConfigKey", { key: "AppFestivalBenefitImg" }).then(function (res) {
|
||||
if (res.code === 0 && res.data) {
|
||||
self.topImage = String(res.data).split(",")[0]
|
||||
}
|
||||
})
|
||||
},
|
||||
listActivity: function () {
|
||||
var self = this
|
||||
this.$axios.post("/platform/home/listHomeActivity").then(function (resp) {
|
||||
if (resp.code === 0) {
|
||||
self.activityOptions = (resp.data || []).filter(function (item) {
|
||||
return self.isWelfareItem(item)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
isWelfareItem: function (item) {
|
||||
var url = ((item && item.url) || "") + "," + ((item && item.h5Url) || "")
|
||||
return url.indexOf("/welfare/") > -1
|
||||
},
|
||||
enterAct: function (item) {
|
||||
if (this.$moment().unix() < this.$moment(item.startDate).unix()) {
|
||||
this.$toast("活动即将开始")
|
||||
return
|
||||
}
|
||||
this.$pjaxReplace(item.h5Url)
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
this.loadTopImage()
|
||||
this.listActivity()
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
body {
|
||||
background-color: #f4f7fb;
|
||||
}
|
||||
|
||||
.festival-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f4f7fb;
|
||||
padding-bottom: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.festival-page /deep/ .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.festival-page /deep/ .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.festival-page /deep/ .van-nav-bar .van-icon,
|
||||
.festival-page /deep/ .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.festival-banner {
|
||||
position: relative;
|
||||
height: 140px;
|
||||
margin: 12px 12px 10px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background-color: #e9eef6;
|
||||
box-shadow: 0 8px 22px rgba(31, 41, 55, .1);
|
||||
}
|
||||
|
||||
.festival-banner img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.festival-banner__shade {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(90deg, rgba(0, 0, 0, .42), rgba(0, 0, 0, .08));
|
||||
}
|
||||
|
||||
.festival-banner__text {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
bottom: 18px;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, .26);
|
||||
}
|
||||
|
||||
.festival-banner__title {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.festival-banner__sub {
|
||||
margin-top: 5px;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
opacity: .92;
|
||||
}
|
||||
|
||||
.festival-list {
|
||||
margin: 0 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 8px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.act-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding: 10px 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.act-item + .act-item {
|
||||
border-top: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.festival-list /deep/ .act-item-wrapper-tag {
|
||||
position: absolute !important;
|
||||
top: 10px !important;
|
||||
left: 12px !important;
|
||||
z-index: 2;
|
||||
width: auto !important;
|
||||
min-width: 42px;
|
||||
height: 20px !important;
|
||||
flex: none !important;
|
||||
padding: 0 6px !important;
|
||||
margin: 0 !important;
|
||||
border: 0 !important;
|
||||
border-radius: 2px !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff !important;
|
||||
background-color: #1f73b7 !important;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
white-space: nowrap !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.festival-list /deep/ .act-item-wrapper-tag.van-tag--success {
|
||||
background-color: #1f73b7 !important;
|
||||
}
|
||||
|
||||
.act-item-cover {
|
||||
width: 120px;
|
||||
height: 84px;
|
||||
flex: 0 0 120px;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
background-color: #f2f3f5;
|
||||
}
|
||||
|
||||
.act-item-cover /deep/ .van-image,
|
||||
.act-item-cover /deep/ img {
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: 84px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.act-item-wrapper {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.content-title {
|
||||
color: #111827;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
font-weight: 600;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
margin-top: 9px;
|
||||
color: #6b7280;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.mt5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
`
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -1,37 +1,88 @@
|
||||
const home = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<van-nav-bar title="首页" class="nav-bar" placeholder fixed></van-nav-bar>
|
||||
<van-swipe :autoplay="100000" :height="200" class="home__swipe">
|
||||
<van-swipe-item>
|
||||
<img src="/assets/mobile/img/home/home1.png" alt="">
|
||||
</van-swipe-item>
|
||||
<van-swipe-item>
|
||||
<img src="/assets/mobile/img/home/home2.png" alt="">
|
||||
</van-swipe-item>
|
||||
<van-swipe-item>
|
||||
<img src="/assets/mobile/img/home/home3.png" alt="">
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
|
||||
<!--快捷入口-->
|
||||
<div class="quick-grid">
|
||||
<div class="section-title">推荐服务</div>
|
||||
<van-grid :column-num="4" icon-size="46" square clickable :border="false">
|
||||
<van-grid-item v-for="item in quickEntries"
|
||||
@click="menuClick(item)"
|
||||
:key="item.id"
|
||||
:text="item.name">
|
||||
<img :src="item.picIcon"
|
||||
slot="icon"
|
||||
style="width: 40px; height: 40px"/>
|
||||
</van-grid-item>
|
||||
</van-grid>
|
||||
<div class="home-hero">
|
||||
<img class="home-hero__bg" :src="currentBanner.src" alt="">
|
||||
<div class="home-hero__mask"></div>
|
||||
<div class="home-hero__logo">
|
||||
<img v-if="appLogo" class="home-hero__logo-img" :src="appLogo" alt="">
|
||||
<div v-else class="home-hero__logo-mark"></div>
|
||||
<div class="home-hero__logo-title" :class="{ 'is-placeholder': !appName }">
|
||||
<span v-if="appName">{{ appName }}</span>
|
||||
<template v-else>
|
||||
<i></i>
|
||||
<i></i>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<van-swipe
|
||||
:autoplay="4000"
|
||||
:height="193"
|
||||
class="home__swipe"
|
||||
indicator-color="#e13b4c"
|
||||
@change="bannerChange">
|
||||
<van-swipe-item v-for="banner in bannerList" :key="banner.src">
|
||||
<div class="home__swipe-card">
|
||||
<img :src="banner.src" alt="">
|
||||
</div>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
</div>
|
||||
|
||||
<!--活动列表-->
|
||||
<div class="act-list">
|
||||
<div class="section-title">最新活动</div>
|
||||
<!--蹇嵎鍏ュ彛-->
|
||||
<div class="quick-grid">
|
||||
<div class="section-title">推荐服务</div>
|
||||
<div class="quick-scroll">
|
||||
<div class="quick-scroll-grid">
|
||||
<div class="quick-entry-item"
|
||||
v-for="item in quickEntries"
|
||||
@click="menuClick(item)"
|
||||
:key="item.id">
|
||||
<div class="quick-entry-icon">
|
||||
<img v-if="item.picIcon" :src="item.picIcon" alt="">
|
||||
<van-icon v-else name="apps-o" size="28"></van-icon>
|
||||
</div>
|
||||
<div class="quick-entry-name">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--娲诲姩鍒楄〃-->
|
||||
<div class="feature-panel">
|
||||
<div
|
||||
class="feature-card"
|
||||
:class="[item.className, { 'feature-card--large': item.large }]"
|
||||
v-for="item in featuredEntries"
|
||||
:key="item.name"
|
||||
@click="featureClick(item)">
|
||||
<div class="feature-card__text">
|
||||
<div class="feature-card__title">{{ item.name }}</div>
|
||||
<div class="feature-card__desc">{{ item.desc }}</div>
|
||||
</div>
|
||||
<van-icon class="feature-card__icon" :name="item.icon"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="classroom-panel" @click="enterClassroom">
|
||||
<div class="classroom-panel__title">我的课堂</div>
|
||||
<div class="classroom-panel__course">{{ currentClassroomCourseName }}</div>
|
||||
<div class="classroom-panel__action">
|
||||
<span>个人学习</span>
|
||||
<van-icon name="arrow"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="policy-panel">
|
||||
<div class="policy-panel__title">政策文件</div>
|
||||
<div class="policy-panel__action">
|
||||
<span>更多</span>
|
||||
<van-icon name="arrow"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="act-list" v-if="showLatestActivity">
|
||||
<div class="section-title section-title--hidden">最新活动</div>
|
||||
<template v-if="activityOptions && activityOptions.length > 0">
|
||||
<div v-for="item in activityOptions" :key="item.id" class="act-item" @click="enterAct(item)">
|
||||
<van-tag class="act-item-wrapper-tag" v-if="$moment().unix() > $moment(item.endDate).unix()">
|
||||
@@ -68,61 +119,759 @@ const home = {
|
||||
data() {
|
||||
return {
|
||||
activityOptions: [],
|
||||
quickEntries: []
|
||||
quickEntries: [],
|
||||
classroomCourses: [],
|
||||
classroomCourseIndex: 0,
|
||||
classroomCourseTimer: null,
|
||||
showLatestActivity: false,
|
||||
featuredEntries: [
|
||||
{
|
||||
name: "精彩活动",
|
||||
desc: "更多精彩活动",
|
||||
icon: "fire-o",
|
||||
className: "feature-card--activity",
|
||||
large: true,
|
||||
href: "/platform/h5/featuredActivity"
|
||||
},
|
||||
{
|
||||
name: "节日福利",
|
||||
desc: "领取节日福利",
|
||||
icon: "gift-o",
|
||||
className: "feature-card--benefit",
|
||||
href: "/platform/h5/festivalBenefit"
|
||||
},
|
||||
{
|
||||
name: "劳模先进",
|
||||
desc: "先进风采展示",
|
||||
icon: "medal-o",
|
||||
className: "feature-card--model",
|
||||
href: "/platform/honor/manage/h5"
|
||||
},
|
||||
{
|
||||
name: "普惠信息",
|
||||
desc: "普惠服务信息",
|
||||
icon: "bullhorn-o",
|
||||
className: "feature-card--inclusive",
|
||||
href: ""
|
||||
}
|
||||
],
|
||||
appLogo: "",
|
||||
appName: "",
|
||||
activeBannerIndex: 0,
|
||||
bannerLoadSeq: 0,
|
||||
bannerImageCache: {},
|
||||
defaultBannerList: [
|
||||
{ src: "/assets/mobile/img/home/home1.png" },
|
||||
{ src: "/assets/mobile/img/home/home2.png" },
|
||||
{ src: "/assets/mobile/img/home/home3.png" }
|
||||
],
|
||||
bannerList: [
|
||||
{ src: "/assets/mobile/img/home/home1.png" },
|
||||
{ src: "/assets/mobile/img/home/home2.png" },
|
||||
{ src: "/assets/mobile/img/home/home3.png" }
|
||||
],
|
||||
homeCachePrefix: "zhgh:h5:home:",
|
||||
homeCacheTtl: {
|
||||
banner: 30 * 60 * 1000,
|
||||
brand: 30 * 60 * 1000,
|
||||
recommend: 10 * 60 * 1000,
|
||||
classroom: 5 * 60 * 1000,
|
||||
activity: 2 * 60 * 1000
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentBanner() {
|
||||
return this.bannerList[this.activeBannerIndex] || this.bannerList[0] || {}
|
||||
},
|
||||
currentClassroomCourseName() {
|
||||
const course = this.classroomCourses[this.classroomCourseIndex]
|
||||
return course && course.courseName ? course.courseName : ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCacheKey(key) {
|
||||
const userId = this.$store && this.$store.state.user ? (this.$store.state.user.id || "anonymous") : "anonymous"
|
||||
return this.homeCachePrefix + userId + ":" + key
|
||||
},
|
||||
readHomeCache(key) {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(this.getCacheKey(key))
|
||||
if (!raw) {
|
||||
return null
|
||||
}
|
||||
const cache = JSON.parse(raw)
|
||||
if (!cache || !cache.expireAt || cache.expireAt < Date.now()) {
|
||||
window.localStorage.removeItem(this.getCacheKey(key))
|
||||
return null
|
||||
}
|
||||
return cache.value
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
},
|
||||
writeHomeCache(key, value, ttl) {
|
||||
try {
|
||||
window.localStorage.setItem(this.getCacheKey(key), JSON.stringify({
|
||||
expireAt: Date.now() + ttl,
|
||||
value: value
|
||||
}))
|
||||
} catch (e) {
|
||||
// Ignore cache quota and private mode errors.
|
||||
}
|
||||
},
|
||||
parseBannerList(value) {
|
||||
if (!value || typeof value !== "string") {
|
||||
return []
|
||||
}
|
||||
return value.split(",")
|
||||
.map(item => item.trim())
|
||||
.filter(item => item)
|
||||
.map(src => ({ src }))
|
||||
},
|
||||
listHomeBanner() {
|
||||
const cached = this.readHomeCache("banner")
|
||||
if (cached && cached.length) {
|
||||
this.bannerList = cached
|
||||
this.activeBannerIndex = 0
|
||||
}
|
||||
this.$axios.post("/open/common/getConfigKey", { key: "AppHomeImg" }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const configBannerList = this.parseBannerList(res.data)
|
||||
const nextBannerList = configBannerList.length > 0 ? configBannerList : this.defaultBannerList
|
||||
this.bannerList = nextBannerList
|
||||
this.activeBannerIndex = 0
|
||||
this.writeHomeCache("banner", nextBannerList, this.homeCacheTtl.banner)
|
||||
this.cacheBannerImages(nextBannerList)
|
||||
}
|
||||
}).catch(() => {
|
||||
if (!cached) {
|
||||
this.bannerList = this.defaultBannerList
|
||||
}
|
||||
})
|
||||
},
|
||||
shouldInlineBanner(src) {
|
||||
return typeof src === "string" && src.indexOf("/platform/sys/file/download") !== -1
|
||||
},
|
||||
cacheBannerImages(list) {
|
||||
const seq = ++this.bannerLoadSeq
|
||||
Promise.all(list.map((banner) => {
|
||||
return this.inlineBannerImage(banner.src).then((src) => Object.assign({}, banner, { src }))
|
||||
})).then((cachedList) => {
|
||||
if (seq === this.bannerLoadSeq) {
|
||||
this.bannerList = cachedList
|
||||
this.activeBannerIndex = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
inlineBannerImage(src) {
|
||||
if (!this.shouldInlineBanner(src)) {
|
||||
return Promise.resolve(src)
|
||||
}
|
||||
if (this.bannerImageCache[src]) {
|
||||
return Promise.resolve(this.bannerImageCache[src])
|
||||
}
|
||||
return fetch(src, {
|
||||
credentials: "same-origin",
|
||||
cache: "force-cache"
|
||||
}).then((resp) => {
|
||||
if (!resp.ok) {
|
||||
throw new Error("load image failed")
|
||||
}
|
||||
return resp.blob()
|
||||
}).then((blob) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => resolve(reader.result)
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
}).then((dataUrl) => {
|
||||
this.bannerImageCache[src] = dataUrl
|
||||
return dataUrl
|
||||
}).catch(() => src)
|
||||
},
|
||||
getConfigValue(key) {
|
||||
return this.$axios.post("/open/common/getConfigKey", { key }).then((res) => {
|
||||
return res.code === 0 ? (res.data || "") : ""
|
||||
}).catch(() => "")
|
||||
},
|
||||
listHomeBrand() {
|
||||
const cached = this.readHomeCache("brand")
|
||||
if (cached) {
|
||||
this.appLogo = cached.appLogo || ""
|
||||
this.appName = cached.appName || ""
|
||||
}
|
||||
Promise.all([
|
||||
this.getConfigValue("AppLogo"),
|
||||
this.getConfigValue("AppName")
|
||||
]).then(([appLogo, appName]) => {
|
||||
this.appLogo = appLogo
|
||||
this.appName = appName
|
||||
this.writeHomeCache("brand", { appLogo, appName }, this.homeCacheTtl.brand)
|
||||
})
|
||||
},
|
||||
listRecommendApp() {
|
||||
const cached = this.readHomeCache("recommend")
|
||||
if (cached && cached.length) {
|
||||
this.quickEntries = cached
|
||||
}
|
||||
this.$axios.post("/platform/home/listRecommendService", { platform: "H5" }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.quickEntries = res.data
|
||||
this.writeHomeCache("recommend", res.data || [], this.homeCacheTtl.recommend)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
listActivity() {
|
||||
const cached = this.readHomeCache("activity")
|
||||
if (cached && cached.length) {
|
||||
this.activityOptions = cached
|
||||
}
|
||||
this.$axios.post("/platform/home/listHomeActivity").then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.activityOptions = resp.data
|
||||
this.writeHomeCache("activity", resp.data || [], this.homeCacheTtl.activity)
|
||||
}
|
||||
})
|
||||
},
|
||||
listClassroomCourses() {
|
||||
const cached = this.readHomeCache("classroom")
|
||||
if (cached && cached.length) {
|
||||
this.classroomCourses = cached
|
||||
this.classroomCourseIndex = 0
|
||||
this.startClassroomCourseTimer()
|
||||
}
|
||||
this.$axios.post("/platform/learning/course/display/pageData", {
|
||||
pageNumber: 1,
|
||||
pageSize: 20
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
this.classroomCourses = data.list || []
|
||||
this.classroomCourseIndex = 0
|
||||
this.writeHomeCache("classroom", this.classroomCourses, this.homeCacheTtl.classroom)
|
||||
this.startClassroomCourseTimer()
|
||||
}
|
||||
}).catch(() => {
|
||||
if (!cached) {
|
||||
this.classroomCourses = []
|
||||
this.classroomCourseIndex = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
startClassroomCourseTimer() {
|
||||
if (this.classroomCourseTimer) {
|
||||
clearInterval(this.classroomCourseTimer)
|
||||
this.classroomCourseTimer = null
|
||||
}
|
||||
if (this.classroomCourses.length <= 1) {
|
||||
return
|
||||
}
|
||||
this.classroomCourseTimer = setInterval(() => {
|
||||
this.classroomCourseIndex = (this.classroomCourseIndex + 1) % this.classroomCourses.length
|
||||
}, 3000)
|
||||
},
|
||||
menuClick(item) {
|
||||
this.$pjaxReplace(item.href)
|
||||
},
|
||||
//点击进入活动
|
||||
featureClick(item) {
|
||||
if (item.href) {
|
||||
this.$pjaxReplace(item.href)
|
||||
}
|
||||
},
|
||||
enterClassroom() {
|
||||
this.$pjaxReplace("/platform/learning/course/h5")
|
||||
},
|
||||
bannerChange(index) {
|
||||
this.activeBannerIndex = index
|
||||
},
|
||||
//鐐瑰嚮杩涘叆娲诲姩
|
||||
enterAct(item) {
|
||||
if(this.$moment().unix() < this.$moment(item.startDate).unix()) {
|
||||
this.$toast('活动即将开始')
|
||||
this.$toast("活动即将开始")
|
||||
return
|
||||
}
|
||||
this.$pjaxReplace(item.h5Url)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.listHomeBanner()
|
||||
this.listHomeBrand()
|
||||
this.listRecommendApp()
|
||||
this.listActivity()
|
||||
this.listClassroomCourses()
|
||||
if (this.showLatestActivity) {
|
||||
this.listActivity()
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.classroomCourseTimer) {
|
||||
clearInterval(this.classroomCourseTimer)
|
||||
this.classroomCourseTimer = null
|
||||
}
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.home__swipe .van-swipe-item img {
|
||||
.home-hero {
|
||||
position: relative;
|
||||
min-height: 281px;
|
||||
overflow: hidden;
|
||||
padding: 26px 16px 0;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.home-hero::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 187px;
|
||||
z-index: 1;
|
||||
width: 180%;
|
||||
height: 96px;
|
||||
transform: translateX(-50%);
|
||||
background-color: #fff;
|
||||
border-radius: 50% 50% 0 0 / 100% 100% 0 0;
|
||||
}
|
||||
|
||||
.home-hero__bg {
|
||||
position: absolute;
|
||||
left: -24px;
|
||||
top: -24px;
|
||||
width: calc(100% + 48px);
|
||||
height: 239px;
|
||||
object-fit: cover;
|
||||
filter: blur(20px);
|
||||
transform: scale(1.12);
|
||||
opacity: .88;
|
||||
transition: opacity .25s ease;
|
||||
}
|
||||
|
||||
.home-hero__mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 239px;
|
||||
background: rgba(0, 0, 0, .06);
|
||||
}
|
||||
|
||||
.home-hero__logo {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
margin-bottom: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.home-hero__logo-mark {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border: 1px solid rgba(255, 255, 255, .72);
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, .2);
|
||||
backdrop-filter: blur(2px);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.home-hero__logo-img {
|
||||
display: block;
|
||||
max-width: 210px;
|
||||
max-height: 36px;
|
||||
object-fit: contain;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.home-hero__logo-title {
|
||||
min-width: 0;
|
||||
margin-left: 10px;
|
||||
color: #fff;
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
text-shadow: 0 1px 8px rgba(0, 0, 0, .24);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.home-hero__logo-title.is-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
width: 154px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.home-hero__logo-title i {
|
||||
display: block;
|
||||
height: 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, .72);
|
||||
}
|
||||
|
||||
.home-hero__logo-title i + i {
|
||||
width: 66%;
|
||||
height: 7px;
|
||||
opacity: .75;
|
||||
}
|
||||
|
||||
.home__swipe {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: visible;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.home__swipe-card {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: rgba(255, 255, 255, .26);
|
||||
box-shadow: 0 10px 28px rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.home__swipe-card img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.home__swipe /deep/ .van-swipe__track,
|
||||
.home__swipe /deep/ .van-swipe-item {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.home__swipe /deep/ .van-swipe__indicators {
|
||||
bottom: -14px;
|
||||
}
|
||||
|
||||
.home__swipe /deep/ .van-swipe__indicator {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: rgba(225, 59, 76, .28);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.home__swipe /deep/ .van-swipe__indicator--active {
|
||||
background-color: #e13b4c;
|
||||
}
|
||||
|
||||
.quick-grid {
|
||||
background-color: #fff;
|
||||
margin: 10px;
|
||||
margin: 10px 10px 10px;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.quick-grid .van-grid-item .van-grid-item__text {
|
||||
.quick-scroll {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
.quick-scroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.quick-scroll-grid {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-template-rows: repeat(2, 82px);
|
||||
grid-auto-columns: 25%;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.quick-entry-item {
|
||||
min-width: 0;
|
||||
height: 82px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.quick-entry-item:active {
|
||||
background-color: #f2f7ff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.quick-entry-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 7px;
|
||||
color: #1989fa;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-entry-icon img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.quick-entry-name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 85%;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
color: #323233;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.feature-panel {
|
||||
margin: 10px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
grid-auto-rows: 82px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
padding: 14px 12px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
min-width: 0;
|
||||
box-shadow: 0 6px 18px rgba(42, 65, 92, .08);
|
||||
}
|
||||
|
||||
.feature-card:active {
|
||||
transform: scale(.985);
|
||||
}
|
||||
|
||||
.feature-card--large {
|
||||
grid-column: span 2;
|
||||
grid-row: span 2;
|
||||
}
|
||||
|
||||
.feature-card__text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.feature-card__title {
|
||||
font-size: 17px;
|
||||
line-height: 22px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.feature-card__desc {
|
||||
color: rgba(55, 65, 81, .64);
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.feature-card__icon {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
bottom: 12px;
|
||||
font-size: 36px;
|
||||
opacity: .78;
|
||||
}
|
||||
|
||||
.feature-card--large .feature-card__icon {
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
font-size: 56px;
|
||||
}
|
||||
|
||||
.feature-card--benefit,
|
||||
.feature-card--model {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.feature-card--benefit .feature-card__desc,
|
||||
.feature-card--model .feature-card__desc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.feature-card--benefit .feature-card__title,
|
||||
.feature-card--model .feature-card__title {
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 0;
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.feature-card--benefit .feature-card__icon,
|
||||
.feature-card--model .feature-card__icon {
|
||||
position: static;
|
||||
display: block;
|
||||
margin: 8px auto 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.feature-card--inclusive .feature-card__icon {
|
||||
font-size: 44px;
|
||||
}
|
||||
|
||||
.feature-card--activity {
|
||||
background: linear-gradient(145deg, #fff2e5 0%, #ffe2c8 100%);
|
||||
color: #ff7a25;
|
||||
}
|
||||
|
||||
.feature-card--benefit {
|
||||
background: linear-gradient(145deg, #fff1f4 0%, #ffd5dc 100%);
|
||||
color: #f35f74;
|
||||
}
|
||||
|
||||
.feature-card--model {
|
||||
background: linear-gradient(145deg, #eef5ff 0%, #d9e8ff 100%);
|
||||
color: #5b83d7;
|
||||
}
|
||||
|
||||
.feature-card--inclusive {
|
||||
grid-column: span 2;
|
||||
background: linear-gradient(145deg, #f2eeff 0%, #ded4ff 100%);
|
||||
color: #8063dc;
|
||||
}
|
||||
|
||||
.classroom-panel {
|
||||
height: 66px;
|
||||
margin: 10px;
|
||||
padding: 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 8px 22px rgba(42, 65, 92, .07);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.classroom-panel:active {
|
||||
transform: scale(.99);
|
||||
}
|
||||
|
||||
.classroom-panel__title {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
color: #202124;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.classroom-panel__title::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -5px;
|
||||
width: 22px;
|
||||
height: 2px;
|
||||
border-radius: 999px;
|
||||
background-color: #e13b4c;
|
||||
}
|
||||
|
||||
.classroom-panel__course {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
margin: 0 12px;
|
||||
color: #1989fa;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.classroom-panel__action {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
color: #969799;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.classroom-panel__action .van-icon {
|
||||
flex-shrink: 0;
|
||||
margin-left: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.policy-panel {
|
||||
height: 66px;
|
||||
margin: 10px;
|
||||
padding: 0 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-radius: 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 8px 22px rgba(42, 65, 92, .07);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.policy-panel__title {
|
||||
position: relative;
|
||||
color: #202124;
|
||||
font-size: 15px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.policy-panel__title::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -5px;
|
||||
width: 22px;
|
||||
height: 2px;
|
||||
border-radius: 999px;
|
||||
background-color: #e13b4c;
|
||||
}
|
||||
|
||||
.policy-panel__action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #969799;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.policy-panel__action .van-icon {
|
||||
margin-left: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.act-list {
|
||||
@@ -190,10 +939,15 @@ const home = {
|
||||
padding: 0 0 5px 5px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.section-title--hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/deep/ .home__swipe img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
/deep/ .act-item-cover img {
|
||||
|
||||
@@ -22,10 +22,10 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
<div id="page-tarbar" class="page-tarbar">
|
||||
<van-tabbar v-model="homeTabbarActive" @change="homeTabbarChange">
|
||||
<van-tabbar-item name="home" icon="wap-home-o">首页</van-tabbar-item>
|
||||
<van-tabbar-item name="apps" icon="apps-o">应用</van-tabbar-item>
|
||||
<!-- <van-tabbar-item name="work" icon="gem">工作台</van-tabbar-item>-->
|
||||
<van-tabbar-item name="todo" icon="records-o">待办</van-tabbar-item>
|
||||
<van-tabbar-item name="home" icon="wap-home-o">首页</van-tabbar-item>
|
||||
<van-tabbar-item name="msg" icon="envelop-o">消息</van-tabbar-item>
|
||||
<van-tabbar-item name="mine" icon="user-o">我的</van-tabbar-item>
|
||||
</van-tabbar>
|
||||
|
||||