This commit is contained in:
张成
2026-04-28 18:11:17 +08:00
parent 335a513571
commit 9c233e5281
10 changed files with 100 additions and 81 deletions

2
.env.development Normal file
View File

@@ -0,0 +1,2 @@
VUE_APP_IMAGE_BASE=
VUE_APP_IMAGE_VERSION=dev

2
.env.production Normal file
View File

@@ -0,0 +1,2 @@
VUE_APP_IMAGE_BASE=https://bimwe.oss-cn-shanghai.aliyuncs.com/web
VUE_APP_IMAGE_VERSION=20260428

BIN
public/foundry_1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

View File

@@ -6,7 +6,7 @@
<div class="footer-main"> <div class="footer-main">
<div class="footer-section"> <div class="footer-section">
<div class="footer-logo"> <div class="footer-logo">
<img :src="require('@/assets/img/logo.png')" alt="丙维科技" class="logo"> <img :src="img('logo.svg')" alt="丙维科技" class="logo">
<h3>上海丙维数字科技有限公司</h3> <h3>上海丙维数字科技有限公司</h3>
<p class="company-desc">AI 工程交付与企业数字化服务</p> <p class="company-desc">AI 工程交付与企业数字化服务</p>
<router-link to="/index#contact" class="footer-cta">预约咨询</router-link> <router-link to="/index#contact" class="footer-cta">预约咨询</router-link>
@@ -80,6 +80,7 @@
<script> <script>
import { getFooterSolutionsMenu } from '../config/menu' import { getFooterSolutionsMenu } from '../config/menu'
import { img } from '@/utils/image'
export default { export default {
name: 'ifooter', name: 'ifooter',
@@ -91,6 +92,7 @@ export default {
data() { data() {
const icon = (path) => `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">${path}</svg>` const icon = (path) => `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">${path}</svg>`
return { return {
img,
showBackToTop: false, showBackToTop: false,
solutionsMenu: getFooterSolutionsMenu(), solutionsMenu: getFooterSolutionsMenu(),
icons: { icons: {

View File

@@ -109,6 +109,7 @@
<script> <script>
import { getMainMenu } from '../config/menu' import { getMainMenu } from '../config/menu'
import { img } from '@/utils/image'
export default { export default {
name: 'ihead', name: 'ihead',
@@ -123,10 +124,10 @@ export default {
computed: { computed: {
image_paths() { image_paths() {
return { return {
logo: require('@/assets/img/logo.png'), logo: img('logo.svg'),
mobile_logo: require('@/assets/img/logo.png'), mobile_logo: img('logo.svg'),
hamburger: require('@/assets/img/svg/ic-hamburger.svg'), hamburger: img('svg/ic-hamburger.svg'),
arrow_back: require('@/assets/img/svg/ic-arrow-back.svg') arrow_back: img('svg/ic-arrow-back.svg')
} }
} }
}, },

35
src/utils/image.js Normal file
View File

@@ -0,0 +1,35 @@
const normalizeBase = (base) => {
if (!base) return ''
return base.endsWith('/') ? base.slice(0, -1) : base
}
const DEFAULT_IMAGE_BASE = 'https://bimwe.oss-cn-shanghai.aliyuncs.com/web'
const IS_DEV = process.env.NODE_ENV === 'development'
const IMAGE_BASE = normalizeBase(process.env.VUE_APP_IMAGE_BASE || (IS_DEV ? '' : DEFAULT_IMAGE_BASE))
const IMAGE_VERSION = process.env.VUE_APP_IMAGE_VERSION || ''
const localImages = IS_DEV
? require.context('@/assets/img', true, /\.(png|jpe?g|gif|webp|svg)$/i)
: null
const isVersionTarget = (url) => /\.(png|jpe?g)(\?.*)?$/i.test(url)
const appendVersion = (url) => {
if (!IMAGE_VERSION) return url
// data/blob URLs cannot carry query strings safely.
if (typeof url === 'string' && (url.startsWith('data:') || url.startsWith('blob:'))) return url
if (!isVersionTarget(url)) return url
return url.includes('?') ? `${url}&v=${IMAGE_VERSION}` : `${url}?v=${IMAGE_VERSION}`
}
export const img = (name) => {
const cleanName = String(name || '').replace(/^\/+/, '')
if (IS_DEV && !IMAGE_BASE && localImages) {
try {
return appendVersion(localImages(`./${cleanName}`))
} catch (e) {
return appendVersion(`/${cleanName}`)
}
}
return appendVersion(`${IMAGE_BASE}/${cleanName}`)
}

View File

@@ -79,7 +79,7 @@
aria-label="滚动到解决方案" aria-label="滚动到解决方案"
@click="scrollToProducts" @click="scrollToProducts"
> >
<img src="../assets/img/svg/ic-caret.svg" alt="" aria-hidden="true"> <img :src="img('svg/ic-caret.svg')" alt="" aria-hidden="true">
</button> </button>
</div> </div>
@@ -208,24 +208,24 @@
<script> <script>
import ResponsiveHelper from '../static/responsive_helper' import ResponsiveHelper from '../static/responsive_helper'
import { img } from '@/utils/image'
let banner_index0 = require('../assets/img/banner-index0.png') const banner_index0 = img('banner-index0.png')
let banner_index1 = require('../assets/img/banner-index1.png') const banner_index1 = img('banner-index1.png')
let banner_index2 = require('../assets/img/banner-index2.png') const banner_index2 = img('banner-index2.png')
let banner_index3 = require('../assets/img/banner-index3.png') const banner_index3 = img('banner-index3.png')
let boxbg_cleaning = require('../assets/img/boxbg-cleaning.png') const boxbg_cleaning = img('boxbg-cleaning.png')
let boxbg_smartbuildings = require('../assets/img/boxbg-smartbuildings.png') const boxbg_smartbuildings = img('boxbg-smartbuildings.png')
let boxbg_iot = require('../assets/img/boxbg-iot.png') const boxbg_iot = img('boxbg-iot.png')
let boxbg_facilitiesmanagement = require('../assets/img/boxbg-facilitiesmanagement.png') const boxbg_facilitiesmanagement = img('boxbg-facilitiesmanagement.png')
let solution_app_delivery = require('../assets/img/solution-app-delivery.svg') const solution_app_delivery = img('solution-app-delivery.svg')
let solution_mini_program = require('../assets/img/solution-mini-program.svg') const solution_mini_program = img('solution-mini-program.svg')
const partnerLogosContext = require.context('../assets/img/hezuo', false, /\.(png|jpe?g|webp|svg)$/i) const partnerLogos = Array.from({ length: 27 }, (_, index) => {
const partnerLogos = partnerLogosContext const num = String(index + 1).padStart(2, '0')
.keys() return { logo: img(`hezuo/client-${num}.png`) }
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true })) })
.map((key) => ({ logo: partnerLogosContext(key) }))
export default { export default {
@@ -249,6 +249,7 @@ export default {
} }
return { return {
img,
icons, icons,
swiperOption: { swiperOption: {
autoplay: { autoplay: {

View File

@@ -4,7 +4,7 @@
<section class="page-banner"> <section class="page-banner">
<div class="gif-banner" aria-hidden="true"> <div class="gif-banner" aria-hidden="true">
<img src="https://bimwe.oss-cn-shanghai.aliyuncs.com/web/foundry_1.gif" alt="" class="banner-gif"> <img src="/foundry_1.gif" alt="" class="banner-gif">
</div> </div>
<div class="container banner-content"> <div class="container banner-content">
<h1 class="banner-title">解决方案</h1> <h1 class="banner-title">解决方案</h1>

View File

@@ -1,37 +1,39 @@
import aiWorkflowHero from '@/assets/img/ai-workflow-hero.jpg' import { img } from '@/utils/image'
import aiDashboardCard from '@/assets/img/ai-dashboard-card.png'
import financeTrading from '@/assets/img/finance-trading-660x370.png'
import reinventingGraphics from '@/assets/img/reinventing-modern-graphics-fallback.jpg'
import estateHero from '@/assets/img/like-no-place-youve-ever-worked.jpg' const aiWorkflowHero = img('ai-workflow-hero.jpg')
import estateScene1 from '@/assets/img/boxbg-propertyandrealestate.jpg' const aiDashboardCard = img('ai-dashboard-card.png')
import estateScene2 from '@/assets/img/banner-page-about-us-mobile.jpg' const financeTrading = img('finance-trading-660x370.png')
import estateScene3 from '@/assets/img/smart-city-network.png' const reinventingGraphics = img('reinventing-modern-graphics-fallback.jpg')
import iotHero from '@/assets/img/driving-automotive-growth-fallback.jpg' const estateHero = img('like-no-place-youve-ever-worked.jpg')
import iotScene1 from '@/assets/img/iot1.jpg' const estateScene1 = img('boxbg-propertyandrealestate.jpg')
import iotScene2 from '@/assets/img/iot2.jpg' const estateScene2 = img('banner-page-about-us-mobile.jpg')
import iotScene3 from '@/assets/img/boxbg-iot.png' const estateScene3 = img('smart-city-network.png')
import facilityHero from '@/assets/img/supercharging-healthcare-fallback.jpg' const iotHero = img('driving-automotive-growth-fallback.jpg')
import facilityScene1 from '@/assets/img/boxbg-facilitiesmanagement.png' const iotScene1 = img('iot1.jpg')
import facilityScene2 from '@/assets/img/boxbg-smartbuildings.png' const iotScene2 = img('iot2.jpg')
import facilityScene3 from '@/assets/img/chatgpt-image-2026-4-27-15-12-15.png' const iotScene3 = img('boxbg-iot.png')
import integrationHero from '@/assets/img/integration-platform-hero.jpg' const facilityHero = img('supercharging-healthcare-fallback.jpg')
import integrationScene1 from '@/assets/img/boxbg-errands.png' const facilityScene1 = img('boxbg-facilitiesmanagement.png')
import integrationScene2 from '@/assets/img/banner-index2.png' const facilityScene2 = img('boxbg-smartbuildings.png')
import integrationScene3 from '@/assets/img/banner-index3.png' const facilityScene3 = img('chatgpt-image-2026-4-27-15-12-15.png')
import appHero from '@/assets/img/app-delivery-flow.png' const integrationHero = img('integration-platform-hero.jpg')
import appScene1 from '@/assets/img/chatgpt-image-2026-4-27-15-26-26.png' const integrationScene1 = img('boxbg-errands.png')
import appScene2 from '@/assets/img/chatgpt-image-2026-4-27-15-26-22.png' const integrationScene2 = img('banner-index2.png')
import appScene3 from '@/assets/img/chatgpt-image-2026-4-27-15-25-58.png' const integrationScene3 = img('banner-index3.png')
import miniHero from '@/assets/img/mini-program-growth-hero.jpg' const appHero = img('app-delivery-flow.png')
import miniScene1 from '@/assets/img/banner-index1-mobile.jpg' const appScene1 = img('chatgpt-image-2026-4-27-15-26-26.png')
import miniScene2 from '@/assets/img/chatgpt-image-2026-4-27-15-26-06.png' const appScene2 = img('chatgpt-image-2026-4-27-15-26-22.png')
import miniScene3 from '@/assets/img/chatgpt-image-2026-4-27-15-26-14.png' const appScene3 = img('chatgpt-image-2026-4-27-15-25-58.png')
const miniHero = img('mini-program-growth-hero.jpg')
const miniScene1 = img('banner-index1-mobile.jpg')
const miniScene2 = img('chatgpt-image-2026-4-27-15-26-06.png')
const miniScene3 = img('chatgpt-image-2026-4-27-15-26-14.png')
export const solutionImageMap = { export const solutionImageMap = {
aiSolutions: { aiSolutions: {

View File

@@ -8,7 +8,6 @@ const resolve = (dir) => {
const BASE_URL = process.env.NODE_ENV === "development" ? "/" : "/"; const BASE_URL = process.env.NODE_ENV === "development" ? "/" : "/";
const sourceMap = process.env.NODE_ENV === "development"; const sourceMap = process.env.NODE_ENV === "development";
const ResponsiveLoaderSharp = require('responsive-loader/sharp'); const ResponsiveLoaderSharp = require('responsive-loader/sharp');
module.exports = { module.exports = {
publicPath: BASE_URL, publicPath: BASE_URL,
lintOnSave: false, // 是否启用 eslint lintOnSave: false, // 是否启用 eslint
@@ -27,7 +26,8 @@ module.exports = {
.use('file-loader') .use('file-loader')
.loader('file-loader') .loader('file-loader')
.options({ .options({
name: 'assets/svg/[name].[hash:8].[ext]' context: resolve('src/assets/img'),
name: 'images/[path][name].[ext]'
}); });
// 普通图片处理(排除 SVG // 普通图片处理(排除 SVG
@@ -38,37 +38,11 @@ module.exports = {
.options({ .options({
limit: 10000, limit: 10000,
esModule: false, esModule: false,
outputPath: "images/" outputPath: "images/",
context: resolve('src/assets/img'),
name: '[path][name].[ext]'
}); });
// 图片压缩
config.module.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({
bypassOnDebug: true,
mozjpeg: { progressive: true, quality: 60 },
optipng: { enabled: false },
pngquant: { quality: [0.5, 0.6], speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
});
// config.module.rule('responsive-images')
// .test(/\.(png|jpe?g|gif)$/i)
// .use('responsive-loader')
// .loader('responsive-loader')
// .options({
// adapter: ResponsiveLoaderSharp,
// sizes: [1200, 1920], // 超过宽度会生成缩小版本
// quality: 75,
// name: 'images/[name]-[width].[ext]',
// placeholder: false
// });
}, },
configureWebpack: { configureWebpack: {