|
|
@@ -2,7 +2,7 @@
|
|
|
<div class="portal-home min-h-screen bg-[#eef3f9] text-[#17345f]">
|
|
|
<Header />
|
|
|
|
|
|
- <main class="mx-auto max-w-[1200px] px-6 pb-8 pt-20">
|
|
|
+ <main class="mx-auto max-w-[1400px] px-3 pb-8 pt-20">
|
|
|
<section class="hero-banner overflow-hidden rounded-[6px] relative">
|
|
|
<div class="">
|
|
|
<!-- 轮播容器 -->
|
|
|
@@ -58,12 +58,39 @@
|
|
|
</div>
|
|
|
</section>
|
|
|
|
|
|
- <section class="mt-3 grid gap-4 xl:grid-cols-[1.74fr_0.74fr]">
|
|
|
+ <section class="portal-mobile-shortcuts mt-3 md:hidden!">
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ class="portal-mobile-shortcut flex flex-col items-center justify-center cursor-pointer"
|
|
|
+ @click="router.push('/flow')"
|
|
|
+ >
|
|
|
+ <img src="../assets//images/flow.png" alt="" class="w-10 h-10" />
|
|
|
+ 流程门户
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ v-hasPermi="['portal:dashboard:view']"
|
|
|
+ type="button"
|
|
|
+ class="portal-mobile-shortcut flex flex-col items-center justify-center cursor-pointer"
|
|
|
+ @click="router.push('/drive')"
|
|
|
+ >
|
|
|
+ <img src="../assets//images/driveicon.png" alt="" class="w-10 h-10" />
|
|
|
+ 驾驶舱门户
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ class="portal-mobile-shortcut flex flex-col items-center justify-center cursor-pointer"
|
|
|
+ >
|
|
|
+ <img src="../assets//images/report.png" alt="" class="w-10 h-10" />
|
|
|
+ 报表门户
|
|
|
+ </button>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <section class="mt-3 grid gap-4 xl:grid-cols-[1.74fr_0.74fr] grid-cols-1">
|
|
|
<div class="space-y-4">
|
|
|
<article
|
|
|
v-for="section in portalSections"
|
|
|
:key="section.code"
|
|
|
- class="platform-block"
|
|
|
+ class="platform-block rounded-sm"
|
|
|
:style="{ minHeight: section.height }"
|
|
|
>
|
|
|
<div class="platform-block__header">
|
|
|
@@ -78,7 +105,7 @@
|
|
|
|
|
|
<div
|
|
|
v-if="section.apps?.length"
|
|
|
- class="grid grid-cols-2 gap-4 p-6 md:grid-cols-4"
|
|
|
+ class="grid grid-cols-[repeat(2,minmax(0,1fr))] gap-2 p-6 px-3 md:px-6 md:grid-cols-[repeat(4,minmax(0,1fr))]"
|
|
|
>
|
|
|
<button
|
|
|
v-for="(app, appIndex) in section.apps"
|
|
|
@@ -105,7 +132,10 @@
|
|
|
class="text-[24px]"
|
|
|
/>
|
|
|
</span>
|
|
|
- <span class="text-[#004098] text-sm">{{ app.label }}</span>
|
|
|
+ <span
|
|
|
+ class="platform-app__label text-[#004098] md:text-sm text-[12px] text-left"
|
|
|
+ >{{ app.label }}</span
|
|
|
+ >
|
|
|
</button>
|
|
|
</div>
|
|
|
</article>
|
|
|
@@ -267,16 +297,16 @@
|
|
|
</section>
|
|
|
|
|
|
<section
|
|
|
+ v-if="userStore.getUser.username"
|
|
|
class="side-card side-card--placeholder rounded-md"
|
|
|
:style="{ minHeight: '78px', backgroundColor: '#3575e4' }"
|
|
|
>
|
|
|
<div class="placeholder-panel flex flex-col text-left">
|
|
|
- <div class="text-sm">需要帮助?</div>
|
|
|
- <div class="text-[10px]">
|
|
|
- 遇到系统操作问题?我们的7 x 24 小时AI助手随时待命。
|
|
|
- </div>
|
|
|
+ <!-- <div class="text-sm">需要帮助?</div> -->
|
|
|
+ <div class="text-[10px]">需要帮助?遇到系统操作问题?</div>
|
|
|
<div
|
|
|
class="bg-white text-sm text-center text-[#004098] py-1 px-2 rounded-full mt-2 w-[30%] cursor-pointer"
|
|
|
+ @click="openConsult"
|
|
|
>
|
|
|
立即咨询
|
|
|
</div>
|
|
|
@@ -291,7 +321,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { computed, onMounted, onUnmounted, ref } from "vue";
|
|
|
+import { computed, onMounted, onUnmounted, reactive, ref } from "vue";
|
|
|
import * as authUtil from "@/utils/auth";
|
|
|
import * as dd from "dingtalk-jsapi";
|
|
|
import Header from "@components/home/header.vue";
|
|
|
@@ -316,7 +346,6 @@ import { manualLogoutKey, reloginCancelKey } from "@/config/axios/service";
|
|
|
import banner1 from "@/assets/images/banner1.png";
|
|
|
import banner2 from "@/assets/images/banner2.jpg";
|
|
|
import banner3 from "@/assets/images/banner3.jpg";
|
|
|
-import img3 from "@/assets/images/3.jpg";
|
|
|
import oaimage from "@/assets/images/oa.jpg";
|
|
|
import crmimage from "@/assets/images/crm.jpg";
|
|
|
import ehrimage from "@/assets/images/ehr.jpg";
|
|
|
@@ -392,17 +421,18 @@ const portalSections: PortalSection[] = [
|
|
|
active: true,
|
|
|
},
|
|
|
{ label: "客户管理(CRM)", image: crmimage },
|
|
|
+ { label: "经营驾驶舱(MC)", image: driveimage },
|
|
|
+ { label: "项目管理(PM)", image: pmimage },
|
|
|
+ { label: "开发需求管理", image: jishuimage2 },
|
|
|
+ { label: "鸿盘", image: hongpan },
|
|
|
{ label: "人力资源(EHR)", image: ehrimage },
|
|
|
{ label: "供应商管理(SRM)", image: scmimage },
|
|
|
{ label: "财务管理(FM)", image: erpimage },
|
|
|
- { label: "经营驾驶舱(MC)", image: driveimage },
|
|
|
- { label: "项目管理(PM)", image: pmimage },
|
|
|
- { label: "技术研发管理", image: jishuimage2 },
|
|
|
+
|
|
|
+ { label: "技术研发管理(R&D)", image: jishuimage2 },
|
|
|
{ label: "战略解码与执行", image: zhanlueimage },
|
|
|
{ label: "组织资产管理", image: zuzhiimage },
|
|
|
{ label: "风控合规管理", image: safeimage },
|
|
|
- { label: "研发需求管理", image: jishuimage2 },
|
|
|
- { label: "鸿盘", image: hongpan },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
|
@@ -416,10 +446,10 @@ const portalSections: PortalSection[] = [
|
|
|
{ label: "质量安全管理(QHSE)", image: qhseimage },
|
|
|
{ label: "智慧连油", image: lianyouimage },
|
|
|
{ label: "智慧注气", image: zhuqiimage },
|
|
|
+ { label: "视频中心(VCS)", image: videoimage },
|
|
|
{ label: "智能钻井", image: zuanjingimage },
|
|
|
{ label: "智慧压裂", image: yalieimage },
|
|
|
{ label: "数字油藏", image: youimage },
|
|
|
- { label: "视频中心(VCS)", image: videoimage },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
|
@@ -447,10 +477,11 @@ let boldLabes = ref([
|
|
|
"质量安全管理(QHSE)",
|
|
|
"智慧注气",
|
|
|
"视频中心(VCS)",
|
|
|
- "研发需求管理",
|
|
|
+ "开发需求管理",
|
|
|
"经营驾驶舱(MC)",
|
|
|
"项目管理(PM)",
|
|
|
"鸿盘",
|
|
|
+ "智能钻井",
|
|
|
]);
|
|
|
|
|
|
const getGreeting = () => {
|
|
|
@@ -634,7 +665,7 @@ const handlePortalAppClick = async (app: PortalApp) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (app.label === "研发需求管理") {
|
|
|
+ if (app.label === "开发需求管理") {
|
|
|
if (userStore.getUser.username && getAccessToken()) {
|
|
|
const res = await zentaoSsoLogin({
|
|
|
username: userStore.getUser.username,
|
|
|
@@ -650,6 +681,14 @@ const handlePortalAppClick = async (app: PortalApp) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (app.label === "智能钻井") {
|
|
|
+ if (userStore.getUser.username && getAccessToken()) {
|
|
|
+ window.open(`http://172.21.0.224:8001/#/login`, "_blank");
|
|
|
+ } else {
|
|
|
+ router.push({ path: "/login" });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (app.label === "鸿盘") {
|
|
|
if (userStore.getUser.username && getAccessToken()) {
|
|
|
window.open(`https://pan.keruioil.com:52180`, "_blank");
|
|
|
@@ -841,6 +880,52 @@ const handleTask = async (row) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+const openConsult = async () => {
|
|
|
+ const res = await ssoLogin({
|
|
|
+ username: userStore.getUser.username,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res) {
|
|
|
+ const ua = window.navigator.userAgent.toLowerCase();
|
|
|
+ if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
|
|
|
+ dd.biz.util.openLink({
|
|
|
+ url:
|
|
|
+ "https://yfoa.keruioil.com/wui/index.html" +
|
|
|
+ "?ssoToken=" +
|
|
|
+ res +
|
|
|
+ "#/main", // 先跳你的 SSO 链接
|
|
|
+ onSuccess: () => {
|
|
|
+ // 延迟跳目标业务地址(和你原来 setTimeout 逻辑一致)
|
|
|
+ setTimeout(() => {
|
|
|
+ dd.biz.util.openLink({
|
|
|
+ url: `https://yfoa.keruioil.com/spa/workflow/static4form/index.html?_rdm=1778289187850#/main/workflow/req?iscreate=1&workflowid=488`,
|
|
|
+ });
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ const loading = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: "正在跳转,请稍候...",
|
|
|
+ background: "rgba(0, 0, 0, 0.7)",
|
|
|
+ });
|
|
|
+ const newTab = window.open("", "_blank");
|
|
|
+ newTab.location.href =
|
|
|
+ "https://yfoa.keruioil.com/wui/index.html" +
|
|
|
+ "?ssoToken=" +
|
|
|
+ res +
|
|
|
+ "#/main";
|
|
|
+
|
|
|
+ setTimeout(function () {
|
|
|
+ newTab.location.href = `https://yfoa.keruioil.com/spa/workflow/static4form/index.html?_rdm=1778289187850#/main/workflow/req?iscreate=1&workflowid=488`;
|
|
|
+ setTimeout(() => {
|
|
|
+ loading.close();
|
|
|
+ }, 500);
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
const goNews = () => {
|
|
|
router.push("/news");
|
|
|
};
|
|
|
@@ -1069,12 +1154,17 @@ onUnmounted(() => {
|
|
|
display: flex;
|
|
|
align-items: baseline;
|
|
|
gap: 28px;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
|
|
|
.platform-block__title {
|
|
|
color: #fff;
|
|
|
font-size: 18px;
|
|
|
-
|
|
|
+ min-width: 0;
|
|
|
+ flex: 0 1 auto;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
letter-spacing: 0.03em;
|
|
|
}
|
|
|
|
|
|
@@ -1082,6 +1172,8 @@ onUnmounted(() => {
|
|
|
color: rgba(255, 255, 255, 0.95);
|
|
|
font-size: 13px;
|
|
|
font-weight: 600;
|
|
|
+ flex: 0 0 auto;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.platform-block__watermark {
|
|
|
@@ -1094,12 +1186,15 @@ onUnmounted(() => {
|
|
|
|
|
|
.platform-app {
|
|
|
display: flex;
|
|
|
+ width: 100%;
|
|
|
+ min-width: 0;
|
|
|
min-height: 34px;
|
|
|
align-items: center;
|
|
|
justify-content: flex-start;
|
|
|
- gap: 12px;
|
|
|
+ gap: 5px;
|
|
|
border-radius: 8px;
|
|
|
- padding: 0 18px;
|
|
|
+ padding: 0 5px;
|
|
|
+
|
|
|
font-size: 14px;
|
|
|
cursor: pointer;
|
|
|
|
|
|
@@ -1130,8 +1225,35 @@ onUnmounted(() => {
|
|
|
color: currentColor;
|
|
|
}
|
|
|
|
|
|
+.platform-app__label {
|
|
|
+ min-width: 0;
|
|
|
+ flex: 1;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+
|
|
|
+.portal-mobile-shortcuts {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.portal-mobile-shortcut {
|
|
|
+ min-width: 0;
|
|
|
+ border: 0;
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 10px 8px;
|
|
|
+ background: linear-gradient(180deg, #ffffff 0%, #5b90e4 100%);
|
|
|
+ color: #0d4a9d;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+ box-shadow: 0 6px 16px rgba(58, 110, 187, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
.side-card {
|
|
|
overflow: hidden;
|
|
|
+
|
|
|
background: #e8f1f8;
|
|
|
/* box-shadow: 0 12px 28px rgba(58, 110, 187, 0.06); */
|
|
|
}
|
|
|
@@ -1385,4 +1507,61 @@ onUnmounted(() => {
|
|
|
transition: all 0.3s ease;
|
|
|
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8);
|
|
|
}
|
|
|
+
|
|
|
+.carousel-container {
|
|
|
+ position: relative;
|
|
|
+ /* 确保容器在移动端有合适的高度,或者使用 aspect-ratio */
|
|
|
+ height: 220px;
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.carousel-slide {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0; /* 确保填满父容器 */
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.hero-visual {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0; /* 关键:让背景层填满整个 slide */
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.hero-visual img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ /* 关键修改:使用 cover 确保图片填满容器且不留白,即使部分被裁剪 */
|
|
|
+ object-fit: cover;
|
|
|
+ /* 如果希望完整显示图片但可能有留白,改用 object-fit: contain; 但通常 banner 推荐 cover */
|
|
|
+ display: block; /* 消除 img 默认的底部间隙 */
|
|
|
+}
|
|
|
+
|
|
|
+/* 移动端适配优化 */
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .carousel-container {
|
|
|
+ /* 移动端可以适当减小高度,或者保持比例 */
|
|
|
+ height: 220px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .carousel-caption {
|
|
|
+ /* 移动端调整文字位置,避免遮挡图片或超出屏幕 */
|
|
|
+ left: 20px;
|
|
|
+ right: 20px;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ text-align: center; /* 移动端居中通常更好看 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .hero-script {
|
|
|
+ font-size: 40px; /* 适当减小字体 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .hero-text {
|
|
|
+ font-size: 16px;
|
|
|
+ margin-top: 10px;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|