Commit aa1ded8ad55ec431c59df947655a0a0c504ac76b
0 parents
feat: 海外官网服务端渲染重构
Showing
39 changed files
with
3348 additions
and
0 deletions
Too many changes to show.
To preserve performance only 39 of 182 files are displayed.
.gitignore
0 → 100644
1 | +++ a/.gitignore | |
1 | +# Nuxt dev/build outputs | |
2 | +.output | |
3 | +.data | |
4 | +.nuxt | |
5 | +.nitro | |
6 | +.cache | |
7 | +dist | |
8 | + | |
9 | +# Node dependencies | |
10 | +node_modules | |
11 | + | |
12 | +# Logs | |
13 | +logs | |
14 | +*.log | |
15 | + | |
16 | +# Misc | |
17 | +.DS_Store | |
18 | +.fleet | |
19 | +.idea | |
20 | + | |
21 | +# Local env files | |
22 | +.env | |
23 | +.env.* | |
24 | +!.env.example | ... | ... |
Dockerfile
0 → 100644
1 | +++ a/Dockerfile | |
1 | +# 使用 Node.js 18 的 Alpine 版本作为基础镜像 | |
2 | +FROM node:18-alpine as build-stage | |
3 | + | |
4 | +# 设置工作目录 | |
5 | +WORKDIR /app | |
6 | + | |
7 | + | |
8 | +# 安装 pnpm | |
9 | +RUN npm install -g pnpm | |
10 | + | |
11 | +# 复制 package.json 和 pnpm-lock.yaml 文件 | |
12 | +COPY package.json pnpm-lock.yaml ./ | |
13 | + | |
14 | +# 安装依赖 | |
15 | +RUN pnpm install --frozen-lockfile --shamefully-hoist | |
16 | + | |
17 | +# 复制项目文件到工作目录 | |
18 | +COPY . . | |
19 | + | |
20 | +ENV NODE_ENV=production | |
21 | +ENV BASE_URL=http://localhost:8002 | |
22 | + | |
23 | +# 构建 Nuxt.js 应用 | |
24 | +RUN pnpm run build | |
25 | + | |
26 | +# 清理阶段 | |
27 | +FROM node:18-alpine as production-stage | |
28 | + | |
29 | +# 设置工作目录 | |
30 | +WORKDIR /app | |
31 | + | |
32 | +# 只复制构建产物 | |
33 | +COPY --from=build-stage /app/.output ./.output | |
34 | + | |
35 | +# 暴露 3000 端口 | |
36 | +EXPOSE 3000 | |
37 | + | |
38 | +# 定义容器启动时执行的命令 | |
39 | +# CMD ["pnpm", "start"] | |
40 | + | |
41 | +CMD ["node", ".output/server/index.mjs"] | |
0 | 42 | \ No newline at end of file | ... | ... |
README.md
0 → 100644
1 | +++ a/README.md | |
1 | +# 启动服务 | |
2 | +pnpm install | |
3 | +pnpm dev | |
4 | + | |
5 | +# 部署到39服务器 | |
6 | +1. 在根目录执行 sh deploy/dev.sh | |
7 | +2. 登录39服务器,进入到 /root/web/canrud-outside-nuxt-front 目录 | |
8 | +3. 在39服务器,依次执行以下命令 | |
9 | +``` | |
10 | +docker load -i canrud-outside-front_dev.tar | |
11 | +docker run -d -p 8088:3000 --name canrud-outside-front canrud-outside-front:dev | |
12 | +``` | |
13 | + | |
14 | +# 生产部署 | |
15 | +1. 在根目录执行 sh deploy/prod.sh | |
16 | +2. 登录112服务器,,将镜像拷贝到生产的47服务器 | |
17 | +scp /root/web/canrud-outside-nuxt-front/canrud-outside-front_1.0.0.tar root@47.89.254.121:/root/web/canrud-outside-nuxt-front | |
18 | +3. 登录47服务器,进入到 /root/web/canrud-outside-nuxt-front 目录 | |
19 | +4. 启动服务 | |
20 | +docker run -d -p 3000:3000 -e BASE_URL=http://localhost:8002 --name canrud-outside-front canrud-outside-front:beta | |
21 | + | |
22 | +docker run -d -p 8088:3000 -e BASE_URL=http://localhost:8002 --name canrud-outside-front canrud-outside-front:1.0.0 | ... | ... |
app.vue
0 → 100644
1 | +++ a/app.vue | |
1 | +<script setup lang="ts"> | |
2 | +import { isMobile } from '~/utils' | |
3 | +import MobileHeader from '~/components/MobileHeader.vue' | |
4 | + | |
5 | +import { useCategoryStore } from '~/stores/category' | |
6 | + | |
7 | +const categoryStore = useCategoryStore() | |
8 | +categoryStore.getList() | |
9 | +</script> | |
10 | + | |
11 | +<template> | |
12 | + <Header v-if="!isMobile()" /> | |
13 | + <MobileHeader v-if="isMobile()" /> | |
14 | + <div class="tw-min-h-[700px]"> | |
15 | + <NuxtPage /> | |
16 | + </div> | |
17 | + <Footer /> | |
18 | +</template> | ... | ... |
assets/css/base.css
0 → 100644
1 | +++ a/assets/css/base.css | |
1 | +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ | |
2 | + | |
3 | +/* Document | |
4 | + ========================================================================== */ | |
5 | + | |
6 | +/** | |
7 | + * 1. Correct the line height in all browsers. | |
8 | + * 2. Prevent adjustments of font size after orientation changes in iOS. | |
9 | + */ | |
10 | + | |
11 | +html { | |
12 | + line-height: 1.15; /* 1 */ | |
13 | + -webkit-text-size-adjust: 100%; /* 2 */ | |
14 | +} | |
15 | + | |
16 | +/* Sections | |
17 | + ========================================================================== */ | |
18 | + | |
19 | +/** | |
20 | + * Remove the margin in all browsers. | |
21 | + */ | |
22 | + | |
23 | +body { | |
24 | + margin: 0; | |
25 | +} | |
26 | + | |
27 | +/** | |
28 | + * Render the `main` element consistently in IE. | |
29 | + */ | |
30 | + | |
31 | +main { | |
32 | + display: block; | |
33 | +} | |
34 | + | |
35 | +/** | |
36 | + * Correct the font size and margin on `h1` elements within `section` and | |
37 | + * `article` contexts in Chrome, Firefox, and Safari. | |
38 | + */ | |
39 | + | |
40 | +h1 { | |
41 | + font-size: 2em; | |
42 | + margin: 0.67em 0; | |
43 | +} | |
44 | + | |
45 | +/* Grouping content | |
46 | + ========================================================================== */ | |
47 | + | |
48 | +/** | |
49 | + * 1. Add the correct box sizing in Firefox. | |
50 | + * 2. Show the overflow in Edge and IE. | |
51 | + */ | |
52 | + | |
53 | +hr { | |
54 | + box-sizing: content-box; /* 1 */ | |
55 | + height: 0; /* 1 */ | |
56 | + overflow: visible; /* 2 */ | |
57 | +} | |
58 | + | |
59 | +/** | |
60 | + * 1. Correct the inheritance and scaling of font size in all browsers. | |
61 | + * 2. Correct the odd `em` font sizing in all browsers. | |
62 | + */ | |
63 | + | |
64 | +pre { | |
65 | + font-family: monospace, monospace; /* 1 */ | |
66 | + font-size: 1em; /* 2 */ | |
67 | +} | |
68 | + | |
69 | +/* Text-level semantics | |
70 | + ========================================================================== */ | |
71 | + | |
72 | +/** | |
73 | + * Remove the gray background on active links in IE 10. | |
74 | + */ | |
75 | + | |
76 | +a { | |
77 | + background-color: transparent; | |
78 | +} | |
79 | + | |
80 | +/** | |
81 | + * 1. Remove the bottom border in Chrome 57- | |
82 | + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. | |
83 | + */ | |
84 | + | |
85 | +abbr[title] { | |
86 | + border-bottom: none; /* 1 */ | |
87 | + text-decoration: underline; /* 2 */ | |
88 | + text-decoration: underline dotted; /* 2 */ | |
89 | +} | |
90 | + | |
91 | +/** | |
92 | + * Add the correct font weight in Chrome, Edge, and Safari. | |
93 | + */ | |
94 | + | |
95 | +b, | |
96 | +strong { | |
97 | + font-weight: bolder; | |
98 | +} | |
99 | + | |
100 | +/** | |
101 | + * 1. Correct the inheritance and scaling of font size in all browsers. | |
102 | + * 2. Correct the odd `em` font sizing in all browsers. | |
103 | + */ | |
104 | + | |
105 | +code, | |
106 | +kbd, | |
107 | +samp { | |
108 | + font-family: monospace, monospace; /* 1 */ | |
109 | + font-size: 1em; /* 2 */ | |
110 | +} | |
111 | + | |
112 | +/** | |
113 | + * Add the correct font size in all browsers. | |
114 | + */ | |
115 | + | |
116 | +small { | |
117 | + font-size: 80%; | |
118 | +} | |
119 | + | |
120 | +/** | |
121 | + * Prevent `sub` and `sup` elements from affecting the line height in | |
122 | + * all browsers. | |
123 | + */ | |
124 | + | |
125 | +sub, | |
126 | +sup { | |
127 | + font-size: 75%; | |
128 | + line-height: 0; | |
129 | + position: relative; | |
130 | + vertical-align: baseline; | |
131 | +} | |
132 | + | |
133 | +sub { | |
134 | + bottom: -0.25em; | |
135 | +} | |
136 | + | |
137 | +sup { | |
138 | + top: -0.5em; | |
139 | +} | |
140 | + | |
141 | +/* Embedded content | |
142 | + ========================================================================== */ | |
143 | + | |
144 | +/** | |
145 | + * Remove the border on images inside links in IE 10. | |
146 | + */ | |
147 | + | |
148 | +img { | |
149 | + border-style: none; | |
150 | +} | |
151 | + | |
152 | +/* Forms | |
153 | + ========================================================================== */ | |
154 | + | |
155 | +/** | |
156 | + * 1. Change the font styles in all browsers. | |
157 | + * 2. Remove the margin in Firefox and Safari. | |
158 | + */ | |
159 | + | |
160 | +button, | |
161 | +input, | |
162 | +optgroup, | |
163 | +select, | |
164 | +textarea { | |
165 | + font-family: inherit; /* 1 */ | |
166 | + font-size: 100%; /* 1 */ | |
167 | + line-height: 1.15; /* 1 */ | |
168 | + margin: 0; /* 2 */ | |
169 | +} | |
170 | + | |
171 | +/** | |
172 | + * Show the overflow in IE. | |
173 | + * 1. Show the overflow in Edge. | |
174 | + */ | |
175 | + | |
176 | +button, | |
177 | +input { | |
178 | + /* 1 */ | |
179 | + overflow: visible; | |
180 | +} | |
181 | + | |
182 | +/** | |
183 | + * Remove the inheritance of text transform in Edge, Firefox, and IE. | |
184 | + * 1. Remove the inheritance of text transform in Firefox. | |
185 | + */ | |
186 | + | |
187 | +button, | |
188 | +select { | |
189 | + /* 1 */ | |
190 | + text-transform: none; | |
191 | +} | |
192 | + | |
193 | +/** | |
194 | + * Correct the inability to style clickable types in iOS and Safari. | |
195 | + */ | |
196 | + | |
197 | +button, | |
198 | +[type='button'], | |
199 | +[type='reset'], | |
200 | +[type='submit'] { | |
201 | + -webkit-appearance: button; | |
202 | +} | |
203 | + | |
204 | +/** | |
205 | + * Remove the inner border and padding in Firefox. | |
206 | + */ | |
207 | + | |
208 | +button::-moz-focus-inner, | |
209 | +[type='button']::-moz-focus-inner, | |
210 | +[type='reset']::-moz-focus-inner, | |
211 | +[type='submit']::-moz-focus-inner { | |
212 | + border-style: none; | |
213 | + padding: 0; | |
214 | +} | |
215 | + | |
216 | +/** | |
217 | + * Restore the focus styles unset by the previous rule. | |
218 | + */ | |
219 | + | |
220 | +button:-moz-focusring, | |
221 | +[type='button']:-moz-focusring, | |
222 | +[type='reset']:-moz-focusring, | |
223 | +[type='submit']:-moz-focusring { | |
224 | + outline: 1px dotted ButtonText; | |
225 | +} | |
226 | + | |
227 | +/** | |
228 | + * Correct the padding in Firefox. | |
229 | + */ | |
230 | + | |
231 | +fieldset { | |
232 | + padding: 0.35em 0.75em 0.625em; | |
233 | +} | |
234 | + | |
235 | +/** | |
236 | + * 1. Correct the text wrapping in Edge and IE. | |
237 | + * 2. Correct the color inheritance from `fieldset` elements in IE. | |
238 | + * 3. Remove the padding so developers are not caught out when they zero out | |
239 | + * `fieldset` elements in all browsers. | |
240 | + */ | |
241 | + | |
242 | +legend { | |
243 | + box-sizing: border-box; /* 1 */ | |
244 | + color: inherit; /* 2 */ | |
245 | + display: table; /* 1 */ | |
246 | + max-width: 100%; /* 1 */ | |
247 | + padding: 0; /* 3 */ | |
248 | + white-space: normal; /* 1 */ | |
249 | +} | |
250 | + | |
251 | +/** | |
252 | + * Add the correct vertical alignment in Chrome, Firefox, and Opera. | |
253 | + */ | |
254 | + | |
255 | +progress { | |
256 | + vertical-align: baseline; | |
257 | +} | |
258 | + | |
259 | +/** | |
260 | + * Remove the default vertical scrollbar in IE 10+. | |
261 | + */ | |
262 | + | |
263 | +textarea { | |
264 | + overflow: auto; | |
265 | +} | |
266 | + | |
267 | +/** | |
268 | + * 1. Add the correct box sizing in IE 10. | |
269 | + * 2. Remove the padding in IE 10. | |
270 | + */ | |
271 | + | |
272 | +[type='checkbox'], | |
273 | +[type='radio'] { | |
274 | + box-sizing: border-box; /* 1 */ | |
275 | + padding: 0; /* 2 */ | |
276 | +} | |
277 | + | |
278 | +/** | |
279 | + * Correct the cursor style of increment and decrement buttons in Chrome. | |
280 | + */ | |
281 | + | |
282 | +[type='number']::-webkit-inner-spin-button, | |
283 | +[type='number']::-webkit-outer-spin-button { | |
284 | + height: auto; | |
285 | +} | |
286 | + | |
287 | +/** | |
288 | + * 1. Correct the odd appearance in Chrome and Safari. | |
289 | + * 2. Correct the outline style in Safari. | |
290 | + */ | |
291 | + | |
292 | +[type='search'] { | |
293 | + -webkit-appearance: textfield; /* 1 */ | |
294 | + outline-offset: -2px; /* 2 */ | |
295 | +} | |
296 | + | |
297 | +/** | |
298 | + * Remove the inner padding in Chrome and Safari on macOS. | |
299 | + */ | |
300 | + | |
301 | +[type='search']::-webkit-search-decoration { | |
302 | + -webkit-appearance: none; | |
303 | +} | |
304 | + | |
305 | +/** | |
306 | + * 1. Correct the inability to style clickable types in iOS and Safari. | |
307 | + * 2. Change font properties to `inherit` in Safari. | |
308 | + */ | |
309 | + | |
310 | +::-webkit-file-upload-button { | |
311 | + -webkit-appearance: button; /* 1 */ | |
312 | + font: inherit; /* 2 */ | |
313 | +} | |
314 | + | |
315 | +/* Interactive | |
316 | + ========================================================================== */ | |
317 | + | |
318 | +/* | |
319 | + * Add the correct display in Edge, IE 10+, and Firefox. | |
320 | + */ | |
321 | + | |
322 | +details { | |
323 | + display: block; | |
324 | +} | |
325 | + | |
326 | +/* | |
327 | + * Add the correct display in all browsers. | |
328 | + */ | |
329 | + | |
330 | +summary { | |
331 | + display: list-item; | |
332 | +} | |
333 | + | |
334 | +/* Misc | |
335 | + ========================================================================== */ | |
336 | + | |
337 | +/** | |
338 | + * Add the correct display in IE 10+. | |
339 | + */ | |
340 | + | |
341 | +template { | |
342 | + display: none; | |
343 | +} | |
344 | + | |
345 | +/** | |
346 | + * Add the correct display in IE 10. | |
347 | + */ | |
348 | + | |
349 | +[hidden] { | |
350 | + display: none; | |
351 | +} | |
352 | + | |
353 | +li { | |
354 | + list-style: none; | |
355 | +} | |
356 | + | |
357 | +a { | |
358 | + color: #fff; | |
359 | + text-decoration: none; | |
360 | +} | ... | ... |
assets/css/main.css
0 → 100644
components/CategoryList.vue
0 → 100644
1 | +++ a/components/CategoryList.vue | |
1 | +<template> | |
2 | + <v-container> | |
3 | + <div class="tw-border tw-border-solid tw-border-[#1f88e5]"> | |
4 | + <v-row | |
5 | + class="ma-0 pl-4 bg-grey-lighten-3 tw-border-0 tw-border-b tw-border-solid tw-border-[#1f88e5] md:tw-leading-[64px]" | |
6 | + > | |
7 | + <div | |
8 | + class="tw-pr-0 tw-font-bold tw-w-[160px] tw-h-[36px] tw-leading-[64px] text-grey-darken-3" | |
9 | + > | |
10 | + CATEGORY: | |
11 | + </div> | |
12 | + <v-col class="flex pa-0" cols="12" sm="9"> | |
13 | + <span | |
14 | + :class="'tw-leading-[50px] tw-inline-flex tw-cursor-pointer px-4 mb-1 mr-1 tw-font-medium rounded hover:tw-text-[#fff] hover:tw-bg-[#1e88e5] ' + | |
15 | + (categoryStore.selectedCategory === item.categoryDisplayName && | |
16 | + 'tw-text-[#fff] tw-bg-[#1e88e5]') | |
17 | + " | |
18 | + v-for="(item, index) in categoryStore.list" | |
19 | + :key="index" | |
20 | + @click="handleCategoryClick(item)" | |
21 | + > | |
22 | + <b class="tw-m-0 tw-inline">{{ item.categoryDisplayName }}</b> | |
23 | + </span> | |
24 | + </v-col> | |
25 | + </v-row> | |
26 | + <v-row class="pa-4 ma-0 bg-grey-lighten-4"> | |
27 | + <div | |
28 | + class="tw-pr-0 tw-font-bold tw-w-[130px] tw-h-[36px] tw-leading-[36px] text-grey-darken-3" | |
29 | + > | |
30 | + DEVICE TYPE: | |
31 | + </div> | |
32 | + <v-col class="pa-0" cols="12" sm="9"> | |
33 | + <span | |
34 | + :class="'px-4 py-1 mb-1 mr-1 tw-font-medium rounded tw-inline-flex tw-cursor-pointer hover:tw-text-[#fff] hover:tw-bg-[#1e88e5] ' + | |
35 | + (categoryStore.selectedSubCategory === item.id && 'tw-text-[#fff] tw-bg-[#1e88e5]') | |
36 | + " | |
37 | + v-for="(item, index) in subCategoryList" | |
38 | + :key="index" | |
39 | + @click="handleSubCategoryClick(item.id)" | |
40 | + > | |
41 | + {{ item.name }} | |
42 | + </span> | |
43 | + </v-col> | |
44 | + </v-row> | |
45 | + <v-row | |
46 | + v-if="funcCategoryList.length" | |
47 | + class="pa-4 ma-0 bg-grey-lighten-4 tw-border-0 tw-border-t tw-border-dashed tw-border-[rgb(178, 178, 178)]" | |
48 | + > | |
49 | + <div | |
50 | + class="tw-pr-0 tw-font-bold tw-w-[210px] tw-h-[36px] tw-leading-[36px] text-grey-darken-3" | |
51 | + > | |
52 | + MATERIAL FUNCTION: | |
53 | + </div> | |
54 | + <v-col class="pa-0" cols="12" sm="9"> | |
55 | + <span | |
56 | + :class="'px-4 py-1 mb-1 mr-1 tw-font-medium rounded tw-inline-flex tw-cursor-pointer hover:tw-text-[#fff] hover:tw-bg-[#1e88e5] ' + | |
57 | + (categoryStore.selectedFuncCategory === item.id && 'tw-text-[#fff] tw-bg-[#1e88e5]') | |
58 | + " | |
59 | + v-for="(item, index) in funcCategoryList" | |
60 | + :key="index" | |
61 | + @click="handleFuncCategoryClick(item.id)" | |
62 | + > | |
63 | + {{ item.name }} | |
64 | + </span> | |
65 | + </v-col> | |
66 | + </v-row> | |
67 | + </div> | |
68 | + </v-container> | |
69 | +</template> | |
70 | + | |
71 | +<script setup lang="ts"> | |
72 | +import { useCategoryStore } from '@/stores/category' | |
73 | +import { useProductListStore } from '@/stores/product_list' | |
74 | +import type { CategoryRootType } from '@/type' | |
75 | +import { computed } from 'vue' | |
76 | +import { useRouter, useRoute } from 'vue-router' | |
77 | + | |
78 | +const router = useRouter() | |
79 | + | |
80 | +const categoryStore = useCategoryStore() | |
81 | +const productStore = useProductListStore() | |
82 | + | |
83 | +const seo = { | |
84 | + 'Energy materials': | |
85 | + 'Energy materials,Not specified,Battery accessories,Lithium-ion batteries,Capacitors,Sodium-ion batteries,Lithium-sulfur batteries,Potassium/magnesium/aluminum/zinc batteries,Air/fuel/solar,Analytical electrodes,Complete battery accessories', | |
86 | + 'Laboratory consumables': | |
87 | + 'Laboratory consumables,Not specified,Glass materials,Plastic materials,Metal materials,Ceramic materials,Paper film materials,Chemical materials,Tetrafluoro materials,Safety protection,Office supplies,Tools,Others', | |
88 | + 'Low-dimensional materials': | |
89 | + ',Low-dimensional materialsNot specified,Zero-dimensional carbon materials,One-dimensional carbon materials,Two-dimensional carbon materials,Three-dimensional carbon materials,Inorganic nanomaterials,Organic nanomaterials,Metal nanomaterials,Others', | |
90 | + Equipment: | |
91 | + 'Equipment,Not specified,Equipment,Accessories & fixtures,Fuel cell manufacturing and testing equipment' | |
92 | +} | |
93 | + | |
94 | +const handleCategoryClick = (item: CategoryRootType) => { | |
95 | + categoryStore.updateCategory(item.categoryDisplayName) | |
96 | + categoryStore.updateSubCategory(item.list[0].id) | |
97 | + productStore.updatePageNo(1) | |
98 | + | |
99 | + router.push({ query: { category: item.categoryDisplayName } }) | |
100 | + | |
101 | + // const doc = document as any | |
102 | + // const head = doc.getElementsByTagName('head') | |
103 | + // const meta = doc.createElement('meta') | |
104 | + // document.title = seo[item.categoryDisplayName as keyof typeof seo] | |
105 | + // doc | |
106 | + // .querySelector('meta[name="keywords"]') | |
107 | + // .setAttribute('content', seo[item.categoryDisplayName as keyof typeof seo]) | |
108 | + // head[0].appendChild(meta) | |
109 | +} | |
110 | + | |
111 | +const handleSubCategoryClick = (value: string) => { | |
112 | + categoryStore.updateSubCategory(value) | |
113 | + productStore.updatePageNo(1) | |
114 | +} | |
115 | + | |
116 | +const handleFuncCategoryClick = (value: string) => { | |
117 | + categoryStore.updateFuncCategory(value) | |
118 | + productStore.updatePageNo(1) | |
119 | +} | |
120 | + | |
121 | +const subCategoryList = computed(() => { | |
122 | + if (categoryStore.selectedCategory) { | |
123 | + const tmp = categoryStore.list.filter( | |
124 | + (item) => item.categoryDisplayName === categoryStore.selectedCategory | |
125 | + ) | |
126 | + return tmp?.[0]?.list || [] | |
127 | + } | |
128 | + return [] | |
129 | +}) | |
130 | + | |
131 | +const funcCategoryList = computed(() => { | |
132 | + if (categoryStore.selectedCategory) { | |
133 | + const tmp = categoryStore.list.filter( | |
134 | + (item) => item.categoryDisplayName === categoryStore.selectedCategory | |
135 | + ) | |
136 | + return tmp?.[0]?.productFunctions || [] | |
137 | + } | |
138 | + return [] | |
139 | +}) | |
140 | +</script> | ... | ... |
components/ContactDialog.vue
0 → 100644
1 | +++ a/components/ContactDialog.vue | |
1 | +<template> | |
2 | + <v-dialog v-model="dialogStore.dialog" width="auto"> | |
3 | + <!-- <v-toolbar color="blue-darken-1" title="Contact Us"></v-toolbar> --> | |
4 | + <v-card class="pt-2 mt-8"> | |
5 | + <v-card-text class="pa-1"> | |
6 | + <span class="text-grey-darken-1 font-weight-medium tw-w-[100px] tw-inline-block tw-text-right">Email: | |
7 | + </span> | |
8 | + <span class="text-grey-darken-4 font-weight-medium"> contact@canrd.com </span> | |
9 | + </v-card-text> | |
10 | + <!-- <v-card-text class="py-2"> | |
11 | + <span | |
12 | + class="text-grey-darken-1 font-weight-medium tw-w-[100px] tw-inline-block tw-text-right" | |
13 | + > | |
14 | + QQ: | |
15 | + </span> | |
16 | + <span class="text-grey-darken-4 font-weight-medium"> 3632191327 </span> | |
17 | + </v-card-text> --> | |
18 | + <v-card-text class="pa-1"> | |
19 | + <span class="text-grey-darken-1 font-weight-medium tw-w-[100px] tw-inline-block tw-text-right"> | |
20 | + Phone: | |
21 | + </span> | |
22 | + <span class="text-grey-darken-4 font-weight-medium"> +86 19867737979 </span> | |
23 | + </v-card-text> | |
24 | + <v-card-text class="pa-1"> | |
25 | + <span class="text-grey-darken-1 font-weight-medium tw-w-[100px] tw-inline-block tw-text-right"> | |
26 | + Telegram: | |
27 | + </span> | |
28 | + <span class="text-grey-darken-4 font-weight-medium"> contactcanrd </span> | |
29 | + </v-card-text> | |
30 | + <v-card-text class="pa-1"> | |
31 | + <span class="text-grey-darken-1 font-weight-medium tw-w-[100px] tw-inline-block tw-text-right"> | |
32 | + Wechat: | |
33 | + </span> | |
34 | + <span class="text-grey-darken-4 font-weight-medium"> contactcanrd </span> | |
35 | + </v-card-text> | |
36 | + <p> | |
37 | + <img src="/wechat.jpg" alt="" width="140" class="tw-m-auto tw-block" /> | |
38 | + </p> | |
39 | + <!-- <v-card-actions class="pa-0"> | |
40 | + <v-btn color="blue-darken-1" block @click="dialogStore.updateDialog(false)">Close </v-btn> | |
41 | + </v-card-actions> --> | |
42 | + </v-card> | |
43 | + </v-dialog> | |
44 | +</template> | |
45 | + | |
46 | +<script setup lang="ts"> | |
47 | +import { useDialogStore } from '~/stores/dialog' | |
48 | +const dialogStore = useDialogStore() | |
49 | + | |
50 | +</script> | |
51 | + | |
52 | +<style lang="less" scoped></style> | ... | ... |
components/ContentDescription.vue
0 → 100644
1 | +++ a/components/ContentDescription.vue | |
1 | +<template> | |
2 | + <div :class="'text-subtitle-1 tw-text-justify font-weight-medium ' + className"> | |
3 | + {{ content }} | |
4 | + </div> | |
5 | +</template> | |
6 | + | |
7 | +<script setup lang="ts"> | |
8 | +defineProps({ | |
9 | + content: String, | |
10 | + className: { | |
11 | + default: 'tw-mb-[64px]', | |
12 | + type: String | |
13 | + } | |
14 | +}) | |
15 | +</script> | ... | ... |
components/Footer.vue
0 → 100644
1 | +++ a/components/Footer.vue | |
1 | +<template> | |
2 | + <div class="bg-grey-darken-3 tw-flex tw-pt-[32px] tw-pb-[32px] text-white"> | |
3 | + <v-container> | |
4 | + <v-row> | |
5 | + <v-col cols="12" lg="3" sm="12" md="6"> | |
6 | + <b>Solution</b> | |
7 | + <p><router-link to="/equipment">Lab Device</router-link></p> | |
8 | + <p><router-link to="/customize">Customized BatterTesting</router-link></p> | |
9 | + <p><router-link to="/pack">Pack</router-link></p> | |
10 | + </v-col> | |
11 | + <v-col cols="12" lg="3" sm="12" md="6"> | |
12 | + <b>Online Product</b> | |
13 | + <p><router-link to="/products">Material Reagents</router-link></p> | |
14 | + <p><router-link to="/products">Lab Device Products</router-link></p> | |
15 | + </v-col> | |
16 | + <v-col cols="12" lg="3" sm="12" md="6"> | |
17 | + <b>About</b> | |
18 | + <p><router-link to="/about">About us</router-link></p> | |
19 | + </v-col> | |
20 | + <v-col cols="12" lg="3" sm="12" md="6"> | |
21 | + <div class="tw-w-[250px] tw-float-left tw-mr-[8px]"> | |
22 | + <b>Contact us</b> | |
23 | + <p>Email: contact@canrd.com</p> | |
24 | + <p>Phone: +86 19867737979</p> | |
25 | + <p>Wechat: contactcanrd</p> | |
26 | + </div> | |
27 | + <img class="tw-float-left" src="/wechat.jpg" width="80" /> | |
28 | + </v-col> | |
29 | + </v-row> | |
30 | + </v-container> | |
31 | + </div> | |
32 | +</template> | |
33 | + | |
34 | +<script setup lang="ts"></script> | |
35 | + | |
36 | +<style> | |
37 | +b { | |
38 | + margin-bottom: 12px; | |
39 | + display: block; | |
40 | +} | |
41 | +p { | |
42 | + cursor: pointer; | |
43 | + margin-bottom: 8px; | |
44 | +} | |
45 | +p a:hover { | |
46 | + color: #e0e0e0; | |
47 | +} | |
48 | +</style> | ... | ... |
components/Header.vue
0 → 100644
1 | +++ a/components/Header.vue | |
1 | +<template> | |
2 | + <v-container> | |
3 | + <v-row class="tw-m-auto tw-flex tw-items-center"> | |
4 | + <v-col cols="2" class="pa-0 tw-h-[64px]"> | |
5 | + <router-link to="/"><v-img src="/logo.jpg" alt="canrud" /></router-link> | |
6 | + </v-col> | |
7 | + <v-col cols="6" md="8" class="px-0"> | |
8 | + <v-text-field label="Search keyword" hide-details="auto" variant="solo" append-inner-icon="mdi-magnify" | |
9 | + @click:appendInner="handleClick" @keydown="handleKeyDown" v-model="input"> | |
10 | + </v-text-field> | |
11 | + </v-col> | |
12 | + <v-col cols="4" md="2" class="px-0"> | |
13 | + <v-btn variant="text" href="/contact" color="blue-darken-2 mt-4">Concat Us | |
14 | + </v-btn> | |
15 | + </v-col> | |
16 | + </v-row> | |
17 | + </v-container> | |
18 | + <div class="tabs"> | |
19 | + <div class="tw-max-w-[1200px] tw-mx-auto"> | |
20 | + <v-tabs mobile-breakpoint="580" v-model="tab" bg-color="blue-darken-1" slider-color="grey-lighten-3" | |
21 | + tab-slider-size="6px" selected-class="active" :grow="screenWidth > 600 ? false : true"> | |
22 | + <v-tab :value="1" to="/"><span @click="handleTabClick" class="text-grey-lighten-3 tw-font-bold">Home</span> | |
23 | + </v-tab> | |
24 | + <v-tab :value="2" to="/products"> | |
25 | + <span @click="handleTabClick" class="text-grey-lighten-3 tw-font-bold">Products</span> | |
26 | + </v-tab> | |
27 | + <v-tab :value="3" to="/about"><span @click="handleTabClick" | |
28 | + class="text-grey-lighten-3 tw-font-bold">About</span> | |
29 | + </v-tab> | |
30 | + <v-tab :value="4" to="/contact"><span @click="handleTabClick" | |
31 | + class="text-grey-lighten-3 tw-font-bold">Contact</span> | |
32 | + </v-tab> | |
33 | + </v-tabs> | |
34 | + </div> | |
35 | + </div> | |
36 | + <ContactDialog /> | |
37 | +</template> | |
38 | + | |
39 | +<script setup lang="ts"> | |
40 | +import { ref, watchEffect } from 'vue' | |
41 | +import ContactDialog from '@/components/ContactDialog.vue' | |
42 | +import { useProductListStore } from '@/stores/product_list' | |
43 | +import { useRouter } from 'vue-router' | |
44 | +import { useDialogStore } from '@/stores/dialog' | |
45 | +import { useCategoryStore } from '@/stores/category' | |
46 | +import { useDisplay } from 'vuetify' | |
47 | + | |
48 | +const { width: screenWidth } = useDisplay() | |
49 | + | |
50 | +const productStore = useProductListStore() | |
51 | +const categoryStore = useCategoryStore() | |
52 | + | |
53 | +const input = ref() | |
54 | + | |
55 | +const router = useRouter() | |
56 | + | |
57 | +const handleKeyDown = (e: any) => { | |
58 | + if (e.keyCode == 13) { | |
59 | + handleClick() | |
60 | + } | |
61 | +} | |
62 | + | |
63 | +const handleClick = () => { | |
64 | + categoryStore.updateDisplay(!input.value) | |
65 | + productStore.updateKeyword(input.value) | |
66 | + productStore.updatePageNo(1) | |
67 | + router.push('/products') | |
68 | +} | |
69 | + | |
70 | +const tab = ref(1) | |
71 | + | |
72 | +const handleTabClick = () => { | |
73 | + categoryStore.updateDisplay(true) | |
74 | + productStore.updateKeyword('') | |
75 | +} | |
76 | + | |
77 | +watchEffect(() => { | |
78 | + input.value = productStore.keyword | |
79 | +}) | |
80 | +</script> | |
81 | + | |
82 | +<style lang="scss" scoped> | |
83 | +.tabs { | |
84 | + background-color: #1f88e5; | |
85 | +} | |
86 | + | |
87 | +.active :deep { | |
88 | + .v-tab__slider { | |
89 | + bottom: 3px; | |
90 | + } | |
91 | +} | |
92 | +</style> | ... | ... |
components/MainTitle.vue
0 → 100644
1 | +++ a/components/MainTitle.vue | |
1 | +<template> | |
2 | + <div :class="'text-blue-darken-1 text-h4 tw-text-center ' + className"> | |
3 | + <b>{{ title }}</b> | |
4 | + </div> | |
5 | +</template> | |
6 | + | |
7 | +<script setup lang="ts"> | |
8 | +defineProps({ | |
9 | + title: String, | |
10 | + className: { default: 'tw-mb-[64px]', type: String } | |
11 | +}) | |
12 | +</script> | |
13 | + | |
14 | +<style lang="less" scoped></style> | ... | ... |
components/MainTitleList.vue
0 → 100644
1 | +++ a/components/MainTitleList.vue | |
1 | +<template> | |
2 | + <div class="text-blue-darken-1 text-h4 text-sm-h3 tw-text-center tw-mb-[16px] font-weight-bold"> | |
3 | + <div :class="titleCls">{{ title }}</div> | |
4 | + </div> | |
5 | + <div class="text-body-1 tw-max-w-[600px] tw-m-auto tw-mb-8"> | |
6 | + <span class="tw-mb-[64px] tw-max-w-[600px] tw-m-auto font-weight-medium text-grey-darken-1">{{ | |
7 | + desc | |
8 | + }}</span> | |
9 | + <router-link :to="href" v-if="href"> | |
10 | + <span | |
11 | + class="font-weight-bold text-decoration-underline tw-inline-block tw-underline tw-text-sky-500 hover:tw-text-sky-800" | |
12 | + >detail | |
13 | + <v-icon class="tw-mt-[-4px]" size="18" icon="mdi-arrow-right"></v-icon> | |
14 | + </span> | |
15 | + </router-link> | |
16 | + </div> | |
17 | + <v-item-group multiple v-if="!responsive"> | |
18 | + <v-row> | |
19 | + <v-col v-for="(item, index) in list" :key="index" cols="6" :lg="lgCol" md="4" sm="6"> | |
20 | + <v-hover v-slot="{ isHovering, props }" open-delay="200" :disabled="disabled"> | |
21 | + <v-card | |
22 | + color="blue-darken-1" | |
23 | + variant="outlined" | |
24 | + :elevation="isHovering ? 16 : 2" | |
25 | + :class="{ 'on-hover': isHovering }" | |
26 | + class="mx-auto" | |
27 | + max-width="260" | |
28 | + v-bind="props" | |
29 | + @click="handleCardClick(item)" | |
30 | + > | |
31 | + <v-img :src="item.imageUrl" :alt="item.name" /> | |
32 | + <div class="text-center bg-blue-darken-1 tw-text-center tw-w-full tw-h-9 tw-leading-9"> | |
33 | + {{ item.name }} | |
34 | + </div> | |
35 | + </v-card> | |
36 | + </v-hover> | |
37 | + </v-col> | |
38 | + </v-row> | |
39 | + </v-item-group> | |
40 | + <v-item-group multiple v-if="responsive"> | |
41 | + <v-row> | |
42 | + <v-col v-for="(item, index) in list" :key="index"> | |
43 | + <v-hover v-slot="{ isHovering, props }" open-delay="200" :disabled="disabled"> | |
44 | + <v-card | |
45 | + color="blue-darken-1" | |
46 | + variant="outlined" | |
47 | + :elevation="isHovering ? 16 : 2" | |
48 | + :class="{ 'on-hover': isHovering }" | |
49 | + class="pt-5 mx-auto" | |
50 | + height="350" | |
51 | + v-bind="props" | |
52 | + :href="item.href ? item.href : undefined" | |
53 | + @click="handleCardClick(item)" | |
54 | + > | |
55 | + <v-img :src="item.imageUrl" width="250" class="text-center ma-auto" /> | |
56 | + <div | |
57 | + class="text-center bg-blue-darken-1 tw-absolute tw-bottom-0 tw-text-center tw-w-full tw-h-9 tw-leading-9" | |
58 | + > | |
59 | + {{ item.name }} | |
60 | + </div> | |
61 | + </v-card> | |
62 | + </v-hover> | |
63 | + </v-col> | |
64 | + </v-row> | |
65 | + </v-item-group> | |
66 | +</template> | |
67 | + | |
68 | +<script setup lang="ts"> | |
69 | +import type { Category } from '@/type' | |
70 | +import { computed } from 'vue' | |
71 | + | |
72 | +import { useCategoryStore } from '@/stores/category' | |
73 | +import { useRouter } from 'vue-router' | |
74 | +import { useProductListStore } from '@/stores/product_list' | |
75 | + | |
76 | +const router = useRouter() | |
77 | +const categoryStore = useCategoryStore() | |
78 | +const productStore = useProductListStore() | |
79 | + | |
80 | +const props = defineProps<{ | |
81 | + title: string | |
82 | + desc?: string | |
83 | + list: Category[] | { name: string; imageUrl?: string; href?: string }[] | |
84 | + cardNum?: number | |
85 | + href?: string | |
86 | + disabled?: boolean | |
87 | + responsive?: boolean | |
88 | + titleCls?: string | |
89 | + titleDivider?: boolean | |
90 | + listType?: string | |
91 | +}>() | |
92 | + | |
93 | +const lgCol = computed(() => (props.cardNum === 3 ? 4 : 3)) | |
94 | + | |
95 | +const handleCardClick = (item: any) => { | |
96 | + if (props.listType !== 'equipment' && item.href) { | |
97 | + router.push(item.href) | |
98 | + } else { | |
99 | + categoryStore.updateCategory(categoryStore.list[3].categoryDisplayName) | |
100 | + categoryStore.updateSubCategory(item.id) | |
101 | + productStore.updatePageNo(1) | |
102 | + router.push(item.href) | |
103 | + } | |
104 | +} | |
105 | +</script> | ... | ... |
components/MainTitleListEquipment.vue
0 → 100644
1 | +++ a/components/MainTitleListEquipment.vue | |
1 | +<template> | |
2 | + <div class="text-blue-darken-1 tw-text-center tw-mb-[16px] font-weight-bold text-h4 text-sm-h3"> | |
3 | + <div :class="titleCls">{{ title }}</div> | |
4 | + </div> | |
5 | + <div class="text-body-1 tw-max-w-[600px] tw-m-auto tw-mb-8"> | |
6 | + <span class="tw-mb-[64px] tw-max-w-[600px] tw-m-auto font-weight-medium text-grey-darken-1">{{ | |
7 | + desc | |
8 | + }}</span> | |
9 | + <router-link :to="href" v-if="href"> | |
10 | + <span | |
11 | + class="font-weight-bold text-decoration-underline tw-inline-block tw-underline tw-text-sky-500 hover:tw-text-sky-800" | |
12 | + >detail | |
13 | + <v-icon class="tw-mt-[-4px]" size="18" icon="mdi-arrow-right"></v-icon> | |
14 | + </span> | |
15 | + </router-link> | |
16 | + </div> | |
17 | + <v-item-group multiple> | |
18 | + <v-row> | |
19 | + <v-col v-for="(item, index) in list" :key="index" cols="6" lg="3" md="4" sm="6"> | |
20 | + <v-hover v-slot="{ isHovering, props }" open-delay="200" :disabled="disabled"> | |
21 | + <v-card | |
22 | + color="blue-darken-1" | |
23 | + variant="outlined" | |
24 | + :elevation="isHovering ? 16 : 2" | |
25 | + :class="{ 'on-hover': isHovering }" | |
26 | + class="pt-5 mx-auto" | |
27 | + v-bind="props" | |
28 | + @click="handleCardClick(item)" | |
29 | + > | |
30 | + <v-img :src="item.imageUrl" class="text-center ma-auto" /> | |
31 | + <div class="text-center bg-blue-darken-1 tw-text-center tw-w-full tw-h-9 tw-leading-9"> | |
32 | + {{ item.name }} | |
33 | + </div> | |
34 | + </v-card> | |
35 | + </v-hover> | |
36 | + </v-col> | |
37 | + </v-row> | |
38 | + </v-item-group> | |
39 | +</template> | |
40 | + | |
41 | +<script setup lang="ts"> | |
42 | +import type { Category } from '@/type' | |
43 | + | |
44 | +import { useCategoryStore } from '@/stores/category' | |
45 | +import { useRouter } from 'vue-router' | |
46 | +import { useProductListStore } from '@/stores/product_list' | |
47 | + | |
48 | +const router = useRouter() | |
49 | +const categoryStore = useCategoryStore() | |
50 | +const productStore = useProductListStore() | |
51 | + | |
52 | +defineProps<{ | |
53 | + title: string | |
54 | + desc?: string | |
55 | + list: Category[] | { name: string; imageUrl?: string; href: string }[] | |
56 | + cardNum?: number | |
57 | + href?: string | |
58 | + disabled?: boolean | |
59 | + responsive?: boolean | |
60 | + titleCls?: string | |
61 | + titleDivider?: boolean | |
62 | +}>() | |
63 | + | |
64 | +const handleCardClick = (item: any) => { | |
65 | + categoryStore.updateCategory(item.name) | |
66 | + const find = categoryStore.list.find((c) => c.categoryDisplayName === item.name)! | |
67 | + categoryStore.updateSubCategory(find.list[0].id) | |
68 | + productStore.updatePageNo(1) | |
69 | + router.push(item.href) | |
70 | +} | |
71 | +</script> | ... | ... |
components/MainTitleListOdd.vue
0 → 100644
1 | +++ a/components/MainTitleListOdd.vue | |
1 | +<template> | |
2 | + <div class="text-blue-darken-1 tw-text-center tw-mb-[16px] font-weight-bold text-h4 text-sm-h3"> | |
3 | + <div :class="titleCls">{{ title }}</div> | |
4 | + </div> | |
5 | + <div class="text-body-1 tw-max-w-[600px] tw-m-auto tw-mb-8"> | |
6 | + <span class="tw-mb-[64px] tw-max-w-[600px] tw-m-auto font-weight-medium text-grey-darken-1">{{ | |
7 | + desc | |
8 | + }}</span> | |
9 | + <router-link :to="href" v-if="href"> | |
10 | + <span | |
11 | + class="font-weight-bold text-decoration-underline tw-inline-block tw-underline tw-text-sky-500 hover:tw-text-sky-800" | |
12 | + >detail | |
13 | + <v-icon class="tw-mt-[-4px]" size="18" icon="mdi-arrow-right"></v-icon> | |
14 | + </span> | |
15 | + </router-link> | |
16 | + </div> | |
17 | + <v-item-group multiple> | |
18 | + <v-row> | |
19 | + <v-col v-for="(item, index) in list" :key="index" cols="4" lg="4" md="4" sm="6"> | |
20 | + <v-hover v-slot="{ isHovering, props }" open-delay="200" :disabled="disabled"> | |
21 | + <v-card | |
22 | + color="blue-darken-1" | |
23 | + variant="outlined" | |
24 | + :elevation="isHovering ? 16 : 2" | |
25 | + :class="{ 'on-hover': isHovering }" | |
26 | + class="pt-5 mx-auto" | |
27 | + v-bind="props" | |
28 | + @click="handleCardClick(item)" | |
29 | + > | |
30 | + <v-img :src="item.imageUrl" class="text-center ma-auto" :alt="item.name" /> | |
31 | + <div class="text-center bg-blue-darken-1 tw-text-center tw-w-full tw-h-9 tw-leading-9"> | |
32 | + {{ item.name }} | |
33 | + </div> | |
34 | + </v-card> | |
35 | + </v-hover> | |
36 | + </v-col> | |
37 | + </v-row> | |
38 | + </v-item-group> | |
39 | +</template> | |
40 | + | |
41 | +<script setup lang="ts"> | |
42 | +import type { Category } from '@/type' | |
43 | + | |
44 | +import { useCategoryStore } from '@/stores/category' | |
45 | +import { useRouter } from 'vue-router' | |
46 | +import { useProductListStore } from '@/stores/product_list' | |
47 | + | |
48 | +const router = useRouter() | |
49 | +const categoryStore = useCategoryStore() | |
50 | +const productStore = useProductListStore() | |
51 | + | |
52 | +defineProps<{ | |
53 | + title: string | |
54 | + desc?: string | |
55 | + list: Category[] | { name: string; imageUrl?: string; href: string }[] | |
56 | + cardNum?: number | |
57 | + href?: string | |
58 | + disabled?: boolean | |
59 | + responsive?: boolean | |
60 | + titleCls?: string | |
61 | + titleDivider?: boolean | |
62 | +}>() | |
63 | + | |
64 | +const handleCardClick = (item: any) => { | |
65 | + categoryStore.updateCategory(item.name) | |
66 | + const find = categoryStore.list.find((c) => c.categoryDisplayName === item.name)! | |
67 | + categoryStore.updateSubCategory(find.list[0].id) | |
68 | + productStore.updatePageNo(1) | |
69 | + router.push(item.href) | |
70 | +} | |
71 | +</script> | ... | ... |
components/MobileCategoryList.vue
0 → 100644
1 | +++ a/components/MobileCategoryList.vue | |
1 | +<template> | |
2 | + <div | |
3 | + class="pr-4 tw-h-[48px] tw-leading-[48px] border-b tw-flex tw-justify-between tw-items-center" | |
4 | + > | |
5 | + <span class="ml-4 tw-font-bold">{{ categoryStore.selectedCategory }}</span> | |
6 | + <span class="ml-1 text-grey-darken-4 text-body-2" @click="drawerVis = !drawerVis" | |
7 | + >Filter <v-icon> mdi-filter-outline </v-icon></span | |
8 | + > | |
9 | + </div> | |
10 | + <!-- <div class="bg-grey-lighten-4 tw-w-full tw-h-3"></div> --> | |
11 | + <v-layout> | |
12 | + <v-navigation-drawer | |
13 | + @update:model-value="handleDrawerHide" | |
14 | + v-model="drawerVis" | |
15 | + location="bottom" | |
16 | + touchless | |
17 | + class="!tw-h-[70%] bg-grey-lighten-4 tw-overflow-y-auto tw-overflow-x-hidden" | |
18 | + > | |
19 | + <div class="mb-4 pa-2 tw-bg-[#fff]" v-for="(item, index) in categoryStore.list" :key="index"> | |
20 | + <div class="mb-4 tw-flex tw-items-center"> | |
21 | + <div> | |
22 | + <v-img | |
23 | + class="mr-4 tw-float-left" | |
24 | + width="32" | |
25 | + :src=" | |
26 | + categoryStore.selectedCategory === item.categoryDisplayName | |
27 | + ? CATEGORY_IMG[index].selected | |
28 | + : CATEGORY_IMG[index].normal | |
29 | + " | |
30 | + ></v-img> | |
31 | + </div> | |
32 | + <strong class="tw-m-0 tw-inline">{{ item.categoryDisplayName }}</strong> | |
33 | + </div> | |
34 | + <div class="tw-flex tw-flex-wrap tw-justify-between"> | |
35 | + <template v-if="index !== 0"> | |
36 | + <div | |
37 | + cols="6" | |
38 | + v-for="(k, i) in item.list" | |
39 | + :class=" | |
40 | + 'tw-w-[48%] mb-4 py-3 px-2 tw-rounded-lg tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis' + | |
41 | + (categoryStore.selectedSubCategory === k.id | |
42 | + ? ' bg-blue-darken-1 text-white ' | |
43 | + : ' bg-grey-lighten-4 ') | |
44 | + " | |
45 | + :key="i" | |
46 | + @click="handleCategoryClick(item, k.id)" | |
47 | + > | |
48 | + {{ k.name }} | |
49 | + </div> | |
50 | + </template> | |
51 | + <template v-else> | |
52 | + <div | |
53 | + cols="6" | |
54 | + v-for="(k, i) in item.productFunctions" | |
55 | + :class=" | |
56 | + (categoryStore.selectedFuncCategory === k.id | |
57 | + ? ' bg-blue-darken-1 text-white ' | |
58 | + : ' bg-grey-lighten-4 ') + | |
59 | + ' tw-w-[48%] mb-4 py-3 px-2 tw-rounded-lg tw-whitespace-nowrap tw-overflow-hidden tw-text-ellipsis' | |
60 | + " | |
61 | + :key="i" | |
62 | + @click="handleCategoryClick(item, k.id)" | |
63 | + > | |
64 | + {{ k.name }} | |
65 | + </div> | |
66 | + </template> | |
67 | + </div> | |
68 | + </div> | |
69 | + </v-navigation-drawer> | |
70 | + </v-layout> | |
71 | +</template> | |
72 | + | |
73 | +<script setup lang="ts"> | |
74 | +import { useCategoryStore } from '@/stores/category' | |
75 | +import { useProductListStore } from '@/stores/product_list' | |
76 | +import type { CategoryRootType } from '@/type' | |
77 | +import { computed, ref, watchEffect } from 'vue' | |
78 | +import { useRouter } from 'vue-router' | |
79 | + | |
80 | +const router = useRouter() | |
81 | + | |
82 | +const categoryStore = useCategoryStore() | |
83 | +const productStore = useProductListStore() | |
84 | + | |
85 | +const drawerVis = ref(false) | |
86 | + | |
87 | +const CATEGORY_IMG = [ | |
88 | + { normal: '/category/1.png', selected: '/category/1.1.png', name: 'Energy materials' }, | |
89 | + { normal: '/category/2.png', selected: '/category/2.1.png', name: 'Laboratory consumables' }, | |
90 | + { normal: '/category/3.png', selected: '/category/3.1.png', name: 'Low-dimensional materials' }, | |
91 | + { normal: '/category/4.png', selected: '/category/4.1.png', name: 'Equipment' } | |
92 | +] | |
93 | + | |
94 | +const SEO = { | |
95 | + 'Energy materials': | |
96 | + 'Energy materials,Not specified,Battery accessories,Lithium-ion batteries,Capacitors,Sodium-ion batteries,Lithium-sulfur batteries,Potassium/magnesium/aluminum/zinc batteries,Air/fuel/solar,Analytical electrodes,Complete battery accessories', | |
97 | + 'Laboratory consumables': | |
98 | + 'Laboratory consumables,Not specified,Glass materials,Plastic materials,Metal materials,Ceramic materials,Paper film materials,Chemical materials,Tetrafluoro materials,Safety protection,Office supplies,Tools,Others', | |
99 | + 'Low-dimensional materials': | |
100 | + ',Low-dimensional materialsNot specified,Zero-dimensional carbon materials,One-dimensional carbon materials,Two-dimensional carbon materials,Three-dimensional carbon materials,Inorganic nanomaterials,Organic nanomaterials,Metal nanomaterials,Others', | |
101 | + Equipment: | |
102 | + 'Equipment,Not specified,Equipment,Accessories & fixtures,Fuel cell manufacturing and testing equipment' | |
103 | +} | |
104 | + | |
105 | +const handleDrawerHide = () => { | |
106 | + productStore.updatePageNo(1) | |
107 | + | |
108 | + router.push({ query: { category: categoryStore.selectedCategory } }) | |
109 | + | |
110 | + const doc = document as any | |
111 | + const head = doc.getElementsByTagName('head') | |
112 | + const meta = doc.createElement('meta') | |
113 | + document.title = SEO[categoryStore.selectedCategory as keyof typeof SEO] | |
114 | + doc | |
115 | + .querySelector('meta[name="keywords"]') | |
116 | + .setAttribute('content', SEO[categoryStore.selectedCategory as keyof typeof SEO]) | |
117 | + head[0].appendChild(meta) | |
118 | +} | |
119 | + | |
120 | +const handleCategoryClick = (item: CategoryRootType, id: string) => { | |
121 | + categoryStore.updateCategory(item.categoryDisplayName) | |
122 | + | |
123 | + if (item.categoryDisplayName === 'Energy materials') { | |
124 | + categoryStore.updateFuncCategory(id) | |
125 | + categoryStore.updateSubCategory(item.list[0].id) | |
126 | + } else { | |
127 | + categoryStore.updateSubCategory(id) | |
128 | + } | |
129 | +} | |
130 | +</script> | |
131 | + | |
132 | +<style lang="less" scoped></style> | ... | ... |
components/MobileHeader.vue
0 → 100644
1 | +++ a/components/MobileHeader.vue | |
1 | +<template> | |
2 | + <!-- <div class="bg-grey-lighten-3 tw-w-full tw-h-[60px]"></div> --> | |
3 | + <!-- color="grey-lighten-3" --> | |
4 | + <v-card class="mx-auto !tw-z-10" max-width="" height="60"> | |
5 | + <v-layout> | |
6 | + <v-app-bar scroll-behavior="elevate" color="white" density="default"> | |
7 | + <v-app-bar-title v-if="!showSearch"> | |
8 | + <a href="/"><v-img src="/mobile/index-logo.png" alt="canrud" width="100" height="40" /></a> | |
9 | + </v-app-bar-title> | |
10 | + <template v-slot:append> | |
11 | + <v-btn icon v-if="!showSearch"> | |
12 | + <v-icon @click="showSearch = !showSearch">mdi-magnify</v-icon> | |
13 | + </v-btn> | |
14 | + | |
15 | + <v-app-bar-nav-icon @click="drawer = !drawer" v-if="!drawer"></v-app-bar-nav-icon> | |
16 | + <v-app-bar-nav-icon @click="drawer = !drawer" v-if="drawer" icon="mdi-window-close"></v-app-bar-nav-icon> | |
17 | + </template> | |
18 | + | |
19 | + <div class="tw-h-[36px] tw-w-[300px] ml-8" v-if="showSearch"> | |
20 | + <v-text-field dense density="compact" height="24" label="Search keyword" hide-details="auto" variant="solo" | |
21 | + append-inner-icon="mdi-close" @click:appendInner="handleClick" @keydown="handleKeyDown" v-model="input"> | |
22 | + </v-text-field> | |
23 | + </div> | |
24 | + </v-app-bar> | |
25 | + | |
26 | + <v-navigation-drawer width="512" v-model="drawer" location="right" temporary floating> | |
27 | + <v-list density="compact" nav> | |
28 | + <v-list-item to="/" title="Home" value="home" @click="handleTabClick" color="blue-darken-1"> | |
29 | + </v-list-item> | |
30 | + <v-divider></v-divider> | |
31 | + <v-list-item to="/products" title="Products" value="Products" @click="handleTabClick" | |
32 | + color="blue-darken-1"></v-list-item> | |
33 | + <v-divider></v-divider> | |
34 | + <v-list-item to="/about" title="About" value="about" @click="handleTabClick" | |
35 | + color="blue-darken-1"></v-list-item> | |
36 | + <v-divider></v-divider> | |
37 | + <v-list-item to="/contact" title="Contact" value="contact" @click="handleTabClick" | |
38 | + color="blue-darken-1"></v-list-item> | |
39 | + </v-list> | |
40 | + </v-navigation-drawer> | |
41 | + </v-layout> | |
42 | + </v-card> | |
43 | + <!-- <v-container> | |
44 | + <v-row class="tw-m-auto tw-flex tw-items-center"> | |
45 | + <v-col cols="2" class="pa-0 tw-h-[64px]"> | |
46 | + <router-link to="/"><v-img src="/logo.jpg" alt="canrud" /></router-link> | |
47 | + </v-col> | |
48 | + <v-col cols="6" md="8" class="px-0"> | |
49 | + <v-text-field | |
50 | + label="Search keyword" | |
51 | + hide-details="auto" | |
52 | + variant="solo" | |
53 | + append-inner-icon="mdi-magnify" | |
54 | + @click:appendInner="handleClick" | |
55 | + @keydown="handleKeyDown" | |
56 | + v-model="input" | |
57 | + > | |
58 | + </v-text-field> | |
59 | + </v-col> | |
60 | + <v-col cols="4" md="2" class="px-0"> | |
61 | + <v-btn variant="text" @click="dialogStore.updateDialog(true)" color="blue-darken-2 mt-4" | |
62 | + >Concat Us | |
63 | + </v-btn> | |
64 | + </v-col> | |
65 | + </v-row> | |
66 | + </v-container> --> | |
67 | + | |
68 | + <ContactDialog /> | |
69 | +</template> | |
70 | + | |
71 | +<script setup lang="ts"> | |
72 | +import { ref, watchEffect } from 'vue' | |
73 | +import { useProductListStore } from '@/stores/product_list' | |
74 | +import { useRouter } from 'vue-router' | |
75 | +import { useDialogStore } from '@/stores/dialog' | |
76 | +import { useCategoryStore } from '@/stores/category' | |
77 | +import { useDisplay } from 'vuetify' | |
78 | + | |
79 | +const drawer = ref(false) | |
80 | +const showSearch = ref(false) | |
81 | + | |
82 | +const productStore = useProductListStore() | |
83 | +const categoryStore = useCategoryStore() | |
84 | + | |
85 | +const input = ref() | |
86 | + | |
87 | +const router = useRouter() | |
88 | + | |
89 | +const handleKeyDown = (e: any) => { | |
90 | + if (e.keyCode == 13) { | |
91 | + categoryStore.updateDisplay(!input.value) | |
92 | + productStore.updateKeyword(input.value) | |
93 | + productStore.updatePageNo(1) | |
94 | + router.push('/products') | |
95 | + } | |
96 | +} | |
97 | + | |
98 | +const handleClick = () => { | |
99 | + showSearch.value = false | |
100 | +} | |
101 | + | |
102 | +const handleTabClick = () => { | |
103 | + categoryStore.updateDisplay(true) | |
104 | + productStore.updateKeyword('') | |
105 | +} | |
106 | + | |
107 | +watchEffect(() => { | |
108 | + input.value = productStore.keyword | |
109 | +}) | |
110 | +</script> | |
111 | + | |
112 | +<style lang="scss" scoped> | |
113 | +.tabs { | |
114 | + background-color: #1f88e5; | |
115 | +} | |
116 | + | |
117 | +.active :deep { | |
118 | + .v-tab__slider { | |
119 | + bottom: 3px; | |
120 | + } | |
121 | +} | |
122 | +</style> | ... | ... |
components/MobileProductDetail.vue
0 → 100644
1 | +++ a/components/MobileProductDetail.vue | |
1 | +<template> | |
2 | + <v-container class="ma-0 pa-0 bg-grey-lighten-5"> | |
3 | + <v-carousel class="tw-float-left" height="450" v-model="slide" hide-delimiter-background> | |
4 | + <v-carousel-item cover v-for="(slide, i) in info.productimageliststore" :src="slide.url" :key="i" | |
5 | + :alt="info.name"> | |
6 | + </v-carousel-item> | |
7 | + </v-carousel> | |
8 | + <div class="mb-3 bg-white mb-sm-10 text-h4 font-weight-medium pa-4"> | |
9 | + {{ info.name }} | |
10 | + </div> | |
11 | + <v-row class="mx-4 mt-0 mb-4 bg-white rounded-lg"> | |
12 | + <v-col cols="6"> | |
13 | + <div class="text-body-1 text-grey-darken-3">Brand:</div> | |
14 | + <div class="text-h6">{{ info.brandName }}</div> | |
15 | + </v-col> | |
16 | + <v-col cols="6"> | |
17 | + <div class="text-body-1 text-grey-darken-3">Product Model:</div> | |
18 | + <div class="text-h6">{{ info.model }}</div> | |
19 | + </v-col> | |
20 | + <v-col cols="6" v-if="info.basename1"> | |
21 | + <div class="text-body-1 text-grey-darken-3">{{ info.basename1 }}:</div> | |
22 | + <div class="text-h6">{{ info.basecore1 }}</div> | |
23 | + </v-col> | |
24 | + <v-col cols="6" v-if="info.basename2"> | |
25 | + <div class="text-body-1 text-grey-darken-3">{{ info.basename2 }}:</div> | |
26 | + <div class="text-h6">{{ info.basecore2 }}</div> | |
27 | + </v-col> | |
28 | + <v-col cols="6" v-if="info.basename3"> | |
29 | + <div class="text-body-1 text-grey-darken-3">{{ info.basename3 }}:</div> | |
30 | + <div class="text-h6">{{ info.basecore3 }}</div> | |
31 | + </v-col> | |
32 | + </v-row> | |
33 | + <div v-if="info.ticketTypes?.length" class="py-4 mx-4 bg-white rounded-lg tw-flex tw-flex-wrap tw-justify-around"> | |
34 | + <v-sheet v-for="item in info.ticketTypes || []" :key="item.rank" rounded="lg" border | |
35 | + class="tw-w-[40%] mb-4"> | |
36 | + <div | |
37 | + class="tw-bg-[#dcecfa] tw-h-[64px] !tw-leading-[64px] rounded-lg rounded-b-0 pa-2 tw-text-center text-h6 tw-overflow-hidden tw-text-ellipsis"> | |
38 | + {{ item.typeName }} | |
39 | + </div> | |
40 | + <div class="tw-h-[82px] pa-2"> | |
41 | + <div class="text-caption">Product Code</div> | |
42 | + <div class="text-body-1 !tw-font-[500]"> | |
43 | + {{ item.rank }} | |
44 | + </div> | |
45 | + </div> | |
46 | + </v-sheet> | |
47 | + <v-btn size="large" color="blue-darken-1" @click="dialogStore.updateDialog(true)"> | |
48 | + Quotation Inquiry | |
49 | + </v-btn> | |
50 | + </div> | |
51 | + <!-- <v-dialog v-model="dialog" activator="parent" width="auto"> | |
52 | + <v-card> Contact us Email: contact@canrd.com QQ: 3003597584 / 2902385824 </v-card> | |
53 | + </v-dialog> --> | |
54 | + <div class="tw-pb-[64px] ma-4 rounded-lg"> | |
55 | + <v-tabs class="tabs" v-model="tab" bg-color="#fff" slider-color="#1d89e4" selected-class="active"> | |
56 | + <v-tab :value="1">Product Details</v-tab> | |
57 | + <v-tab :value="2">Specification</v-tab> | |
58 | + <!-- <v-tab :value="3">商品百科</v-tab> --> | |
59 | + </v-tabs> | |
60 | + <v-window v-model="tab"> | |
61 | + <v-window-item key="1" :value="1"> | |
62 | + <div v-if="info.advantage" class="tw-mb-[24px]"> | |
63 | + <div class="py-2 pl-2 text-h6">Advantage</div> | |
64 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
65 | + <div v-html="info.advantage"></div> | |
66 | + </div> | |
67 | + <div v-if="info.physicalproperty" class="tw-mb-[24px]"> | |
68 | + <div class="py-2 pl-2 text-h6">Physical Property</div> | |
69 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
70 | + <div v-html="info.physicalproperty"></div> | |
71 | + </div> | |
72 | + <div v-if="info.advantage" class="tw-mb-[24px]"> | |
73 | + <div class="py-2 pl-2 text-h6">Storage</div> | |
74 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
75 | + <div v-html="info.storage"></div> | |
76 | + </div> | |
77 | + <div v-if="info.introduction" class="tw-mb-[24px]"> | |
78 | + <div class="py-2 pl-2 text-h6">Introduction</div> | |
79 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
80 | + <div v-html="info.introduction"></div> | |
81 | + </div> | |
82 | + <div v-if="info.advantage" class="tw-mb-[24px]"> | |
83 | + <div class="py-2 pl-2 text-h6">Description</div> | |
84 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
85 | + <div v-html="info.description"></div> | |
86 | + </div> | |
87 | + </v-window-item> | |
88 | + <v-window-item key="2" :value="2"> | |
89 | + <v-table density="compact" class="table2"> | |
90 | + <tbody> | |
91 | + <tr class="tr" v-for="item in info.productAttributeList || []" :key="item.name"> | |
92 | + <td class="td tw-w-[400px]">{{ item.name }}</td> | |
93 | + <td class="td">{{ item.value }}</td> | |
94 | + </tr> | |
95 | + </tbody> | |
96 | + </v-table> | |
97 | + </v-window-item> | |
98 | + <!-- <v-window-item key="3" :value="3"> 2 </v-window-item> --> | |
99 | + </v-window> | |
100 | + </div> | |
101 | + </v-container> | |
102 | +</template> | |
103 | + | |
104 | +<script setup lang="ts"> | |
105 | +import type { Product } from '~/type' | |
106 | +import { onMounted, ref } from 'vue' | |
107 | +import { useDialogStore } from '~/stores/dialog' | |
108 | +const dialogStore = useDialogStore() | |
109 | + | |
110 | +const props = defineProps<{ | |
111 | + info: Product | |
112 | +}>() | |
113 | +const info = props.info | |
114 | +onMounted(() => { | |
115 | + dialogStore.updateDialog(true) | |
116 | +}) | |
117 | +// getDetail({ id: route.params.id as string }).then((res) => { | |
118 | + | |
119 | +// const doc = document as any | |
120 | +// const head = doc.getElementsByTagName('head') | |
121 | +// const meta = doc.createElement('meta') | |
122 | +// document.title = data.name | |
123 | +// doc | |
124 | +// .querySelector('meta[name="keywords"]') | |
125 | +// .setAttribute('content', data.metakeywords || data.name) | |
126 | +// doc | |
127 | +// .querySelector('meta[name="description"]') | |
128 | +// .setAttribute('content', data.metadescription || data.name) | |
129 | +// head[0].appendChild(meta) | |
130 | +// }) | |
131 | +// }) | |
132 | + | |
133 | +const tab = ref(0) | |
134 | +const slide = ref(0) | |
135 | +</script> | |
136 | + | |
137 | +<style lang="scss" scoped> | |
138 | +.tabs { | |
139 | + border-bottom: 2px solid #cbd9e4; | |
140 | +} | |
141 | + | |
142 | +.active { | |
143 | + background-color: #fff; | |
144 | +} | |
145 | +</style> | ... | ... |
components/ProductDetail.vue
0 → 100644
1 | +++ a/components/ProductDetail.vue | |
1 | +<template> | |
2 | + <v-container> | |
3 | + <v-row class="mb-16 ma-0"> | |
4 | + <v-col cols="12" sm="5"> | |
5 | + <v-carousel class="tw-float-left" height="450" v-model="slide" hide-delimiter-background> | |
6 | + <v-carousel-item cover v-for="(slide, i) in info.productimageliststore" :src="slide.url" :key="i" | |
7 | + :alt="info.name"> | |
8 | + </v-carousel-item> | |
9 | + </v-carousel> | |
10 | + </v-col> | |
11 | + <v-col cols="12" sm="7"> | |
12 | + <v-row class="bg-white mb-sm-10 text-h4 font-weight-medium"> | |
13 | + <v-col>{{ info.name }}</v-col> | |
14 | + </v-row> | |
15 | + <div class="tw-flex tw-flex-wrap"> | |
16 | + <div class="tw-w-1/2"> | |
17 | + <span class="tw-leading-[10px] tw-m-[16px]"> Brand:{{ info.brandName }} </span> | |
18 | + </div> | |
19 | + <div class="tw-w-1/2 tw-mb-[12px]"> | |
20 | + <span class="tw-leading-[10px] tw-m-[16px]">Product Model:{{ info.model }}</span> | |
21 | + </div> | |
22 | + <div class="tw-w-1/2 tw-mb-[12px]" v-if="info.basename1"> | |
23 | + <span class="tw-leading-[10px] tw-m-[16px]">{{ info.basename1 }}:{{ info.basecore1 }}</span> | |
24 | + </div> | |
25 | + <div class="tw-w-1/2 tw-mb-[12px]" v-if="info.basename2"> | |
26 | + <span class="tw-leading-[10px] tw-m-[16px]">{{ info.basename2 }}:{{ info.basecore2 }}</span> | |
27 | + </div> | |
28 | + <div class="tw-w-1/2 tw-mb-[12px]" v-if="info.basename3"> | |
29 | + <span class="tw-leading-[10px] tw-m-[16px]">{{ info.basename3 }}:{{ info.basecore3 }}</span> | |
30 | + </div> | |
31 | + </div> | |
32 | + <v-table density="comfortable" class="table1 tw-mt-[32px]" v-if="info.ticketTypes?.length"> | |
33 | + <thead> | |
34 | + <tr class="bg-grey-lighten-3"> | |
35 | + <th class="text-left headerBorder text-grey-darken-1">Product Name / Code</th> | |
36 | + <th class="text-left headerBorder text-grey-darken-1">Specification and model</th> | |
37 | + <th class="text-left headerBorder text-grey-darken-1">Price</th> | |
38 | + </tr> | |
39 | + </thead> | |
40 | + <tbody> | |
41 | + <tr class="tr" v-for="item in info.ticketTypes || []" :key="item.rank"> | |
42 | + <td class="td text-grey-darken-4 font-weight-medium">{{ item.rank }}</td> | |
43 | + <td class="td text-grey-darken-4 font-weight-medium">{{ item.typeName }}</td> | |
44 | + <!-- <td class="td">{{ item.price }}</td> --> | |
45 | + <td class="td"> | |
46 | + <v-btn size="small" color="blue-darken-1" @click="dialogStore.updateDialog(true)"> | |
47 | + Quotation Inquiry | |
48 | + </v-btn> | |
49 | + </td> | |
50 | + </tr> | |
51 | + </tbody> | |
52 | + </v-table> | |
53 | + <!-- <v-dialog v-model="dialog" activator="parent" width="auto"> | |
54 | + <v-card> Contact us Email: contact@canrd.com QQ: 3003597584 / 2902385824 </v-card> | |
55 | + </v-dialog> --> | |
56 | + </v-col> | |
57 | + </v-row> | |
58 | + <div class="tw-pb-[64px]"> | |
59 | + <v-tabs class="tabs" v-model="tab" color="white" bg-color="#eeeeee" slider-color="blue-lighten-1" | |
60 | + selected-class="active"> | |
61 | + <v-tab :value="1">Product Details</v-tab> | |
62 | + <v-tab :value="2">Specification</v-tab> | |
63 | + <!-- <v-tab :value="3">商品百科</v-tab> --> | |
64 | + </v-tabs> | |
65 | + <v-window v-model="tab" class="tw-p-[24px]"> | |
66 | + <v-window-item key="1" :value="1"> | |
67 | + <div v-if="info.advantage" class="tw-mb-[24px]"> | |
68 | + <div class="text-h6">Advantage</div> | |
69 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
70 | + <div v-html="info.advantage"></div> | |
71 | + </div> | |
72 | + <div v-if="info.physicalproperty" class="tw-mb-[24px]"> | |
73 | + <div class="text-h6">Physical Property</div> | |
74 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
75 | + <div v-html="info.physicalproperty"></div> | |
76 | + </div> | |
77 | + <div v-if="info.advantage" class="tw-mb-[24px]"> | |
78 | + <div class="text-h6">Storage</div> | |
79 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
80 | + <div v-html="info.storage"></div> | |
81 | + </div> | |
82 | + <div v-if="info.introduction" class="tw-mb-[24px]"> | |
83 | + <div class="text-h6">Introduction</div> | |
84 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
85 | + <div v-html="info.introduction"></div> | |
86 | + </div> | |
87 | + <div v-if="info.advantage" class="tw-mb-[24px]"> | |
88 | + <div class="text-h6">Description</div> | |
89 | + <v-divider class="tw-mb-[12px]"></v-divider> | |
90 | + <div v-html="info.description"></div> | |
91 | + </div> | |
92 | + </v-window-item> | |
93 | + <v-window-item key="2" :value="2"> | |
94 | + <v-table density="compact" class="table2"> | |
95 | + <tbody> | |
96 | + <tr class="tr" v-for="item in info.productAttributeList || []" :key="item.name"> | |
97 | + <td class="td tw-w-[400px]">{{ item.name }}</td> | |
98 | + <td class="td">{{ item.value }}</td> | |
99 | + </tr> | |
100 | + </tbody> | |
101 | + </v-table> | |
102 | + </v-window-item> | |
103 | + <!-- <v-window-item key="3" :value="3"> 2 </v-window-item> --> | |
104 | + </v-window> | |
105 | + </div> | |
106 | + </v-container> | |
107 | +</template> | |
108 | + | |
109 | +<script setup lang="ts"> | |
110 | +import type { Product, ProductImage } from '~/type' | |
111 | +import { onMounted, ref } from 'vue' | |
112 | +import { useDialogStore } from '~/stores/dialog' | |
113 | +const dialogStore = useDialogStore() | |
114 | + | |
115 | +const props = defineProps<{ | |
116 | + info: Product | |
117 | +}>() | |
118 | +const info = props.info | |
119 | + | |
120 | +onMounted(() => { | |
121 | + console.log('%c [ ]-124', 'font-size:13px; background:pink; color:#bf2c9f;', 111) | |
122 | + dialogStore.updateDialog(true) | |
123 | +}) | |
124 | + | |
125 | +const tab = ref(0) | |
126 | +const slide = ref(0) | |
127 | +</script> | |
128 | + | |
129 | +<style lang="scss" scoped> | |
130 | +.headerBorder { | |
131 | + border-top: 3px solid #1f88e5 !important; | |
132 | +} | |
133 | + | |
134 | +.tabs { | |
135 | + border-bottom: 2px solid #1f88e5; | |
136 | +} | |
137 | + | |
138 | +.active { | |
139 | + background-color: #1086e8; | |
140 | +} | |
141 | + | |
142 | +.td, | |
143 | +th { | |
144 | + border: 1px solid #dcdcdc; | |
145 | + border-right: 0px; | |
146 | + border-bottom: 0px !important; | |
147 | + height: 50px !important; | |
148 | + | |
149 | + &:last-child { | |
150 | + border: 1px solid #dcdcdc; | |
151 | + } | |
152 | +} | |
153 | + | |
154 | +.tr:last-child { | |
155 | + .td { | |
156 | + border-bottom: 1px solid #dcdcdc !important; | |
157 | + } | |
158 | +} | |
159 | +</style> | ... | ... |
components/icons/IconCommunity.vue
0 → 100644
1 | +++ a/components/icons/IconCommunity.vue | |
1 | +<template> | |
2 | + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor"> | |
3 | + <path | |
4 | + d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z" | |
5 | + /> | |
6 | + </svg> | |
7 | +</template> | ... | ... |
components/icons/IconDocumentation.vue
0 → 100644
1 | +++ a/components/icons/IconDocumentation.vue | |
1 | +<template> | |
2 | + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor"> | |
3 | + <path | |
4 | + d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z" | |
5 | + /> | |
6 | + </svg> | |
7 | +</template> | ... | ... |
components/icons/IconEcosystem.vue
0 → 100644
1 | +++ a/components/icons/IconEcosystem.vue | |
1 | +<template> | |
2 | + <svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor"> | |
3 | + <path | |
4 | + d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z" | |
5 | + /> | |
6 | + </svg> | |
7 | +</template> | ... | ... |
components/icons/IconSupport.vue
0 → 100644
1 | +++ a/components/icons/IconSupport.vue | |
1 | +<template> | |
2 | + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor"> | |
3 | + <path | |
4 | + d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z" | |
5 | + /> | |
6 | + </svg> | |
7 | +</template> | ... | ... |
components/icons/IconTooling.vue
0 → 100644
1 | +++ a/components/icons/IconTooling.vue | |
1 | +<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license--> | |
2 | +<template> | |
3 | + <svg | |
4 | + xmlns="http://www.w3.org/2000/svg" | |
5 | + xmlns:xlink="http://www.w3.org/1999/xlink" | |
6 | + aria-hidden="true" | |
7 | + role="img" | |
8 | + class="iconify iconify--mdi" | |
9 | + width="24" | |
10 | + height="24" | |
11 | + preserveAspectRatio="xMidYMid meet" | |
12 | + viewBox="0 0 24 24" | |
13 | + > | |
14 | + <path | |
15 | + d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z" | |
16 | + fill="currentColor" | |
17 | + ></path> | |
18 | + </svg> | |
19 | +</template> | ... | ... |
constant/index.ts
0 → 100644
deploy/dev-run.sh
0 → 100644
1 | +++ a/deploy/dev-run.sh | ... | ... |
deploy/dev.sh
0 → 100644
1 | +++ a/deploy/dev.sh | |
1 | +#!/bin/bash | |
2 | + | |
3 | +# 变量定义 | |
4 | +IMAGE_NAME="canrud-outside-front" | |
5 | +TAG="dev" | |
6 | +TAR_FILE="${IMAGE_NAME}_${TAG}.tar" | |
7 | +REMOTE_HOST="root@39.108.227.113" | |
8 | +REMOTE_DIR="/root/web/canrud-outside-nuxt-front" | |
9 | + | |
10 | +# 步骤1: 构建 Docker 镜像 | |
11 | +echo "Building Docker image..." | |
12 | +docker build -t ${IMAGE_NAME}:${TAG} . | |
13 | + | |
14 | +# 步骤2: 将 Docker 镜像导出为 tar 文件 | |
15 | +echo "Saving Docker image to tar file..." | |
16 | +docker save -o ${TAR_FILE} ${IMAGE_NAME}:${TAG} | |
17 | + | |
18 | +# 步骤3: 上传 tar 文件到服务器 | |
19 | +echo "Uploading tar file to server..." | |
20 | +scp ${TAR_FILE} ${REMOTE_HOST}:${REMOTE_DIR} | |
21 | + | |
22 | +echo "All tasks completed!" | ... | ... |
deploy/prod.sh
0 → 100644
1 | +++ a/deploy/prod.sh | |
1 | +#!/bin/bash | |
2 | + | |
3 | +# 变量定义 | |
4 | +IMAGE_NAME="canrud-outside-front" | |
5 | +TAG="1.0.0" | |
6 | +TAR_FILE="${IMAGE_NAME}_${TAG}.tar" | |
7 | +REMOTE_HOST="root@112.74.45.244" | |
8 | +REMOTE_DIR="/root/web/canrud-outside-nuxt-front" | |
9 | + | |
10 | +# 步骤1: 构建 Docker 镜像 | |
11 | +echo "Building Docker image..." | |
12 | +docker build -t ${IMAGE_NAME}:${TAG} . | |
13 | + | |
14 | +# 步骤2: 将 Docker 镜像导出为 tar 文件 | |
15 | +echo "Saving Docker image to tar file..." | |
16 | +docker save -o ${TAR_FILE} ${IMAGE_NAME}:${TAG} | |
17 | + | |
18 | +# 步骤3: 上传 tar 文件到服务器 | |
19 | +echo "Uploading tar file to server..." | |
20 | +scp ${TAR_FILE} ${REMOTE_HOST}:${REMOTE_DIR} | |
21 | + | |
22 | +echo "All tasks completed!" | ... | ... |
nuxt.config.ts
0 → 100644
1 | +++ a/nuxt.config.ts | |
1 | +// https://nuxt.com/docs/api/configuration/nuxt-config | |
2 | +// Nuxt config file | |
3 | +import { defineNuxtConfig } from 'nuxt/config' | |
4 | + | |
5 | +export default defineNuxtConfig({ | |
6 | + app: { | |
7 | + head: { | |
8 | + link: [ | |
9 | + { rel: 'icon', type: 'image/x-icon', href: '/fav.ico' } | |
10 | + ] | |
11 | + } | |
12 | + }, | |
13 | + css: ['~/assets/css/main.css'], | |
14 | + postcss: { | |
15 | + plugins: { | |
16 | + tailwindcss: {}, | |
17 | + autoprefixer: {}, | |
18 | + }, | |
19 | + }, | |
20 | + // runtimeConfig: { | |
21 | + // public: { | |
22 | + // baseURL: 'http://47.89.254.121:8002/shop' || 'http://39.108.227.113:8002' // Exposed to the frontend as well. | |
23 | + // } | |
24 | + // }, | |
25 | + modules: [ | |
26 | + 'vuetify-nuxt-module', | |
27 | + '@pinia/nuxt', | |
28 | + '@nuxtjs/i18n', | |
29 | + ], | |
30 | + vuetify: { | |
31 | + moduleOptions: { | |
32 | + /* module specific options */ | |
33 | + }, | |
34 | + vuetifyOptions: { | |
35 | + /* vuetify options */ | |
36 | + } | |
37 | + }, | |
38 | + nitro:{ | |
39 | + devProxy: { | |
40 | + '/shop': { | |
41 | + target: 'http://47.89.254.121:8002/shop', // 线上代理地址 | |
42 | + // target: process.env.BASE_URL || 'http://39.108.227.113:8002/shop', // 目标接口域名 | |
43 | + changeOrigin: true, // 表示是否跨域 | |
44 | + } | |
45 | + }, | |
46 | + // 该配置用于服务端请求转发 | |
47 | + routeRules: { | |
48 | + '/shop/**': { | |
49 | + proxy: 'http://47.89.254.121:8002/shop/**' | |
50 | + // proxy: process.env.BASE_URL || 'http://39.108.227.113:8002/shop/**' | |
51 | + } | |
52 | + } | |
53 | + } | |
54 | +}) | |
55 | + | ... | ... |
package.json
0 → 100644
1 | +++ a/package.json | |
1 | +{ | |
2 | + "name": "nuxt-app", | |
3 | + "private": true, | |
4 | + "type": "module", | |
5 | + "scripts": { | |
6 | + "build": "nuxt build", | |
7 | + "dev": "nuxt dev", | |
8 | + "generate": "nuxt generate", | |
9 | + "preview": "nuxt preview", | |
10 | + "postinstall": "nuxt prepare" | |
11 | + }, | |
12 | + "dependencies": { | |
13 | + "@pinia/nuxt": "^0.5.1", | |
14 | + "lodash": "^4.17.21", | |
15 | + "nuxt": "^3.11.2", | |
16 | + "vue": "^3.4.27", | |
17 | + "vue-router": "^4.3.2", | |
18 | + "vuetify-nuxt-module": "^0.14.0" | |
19 | + }, | |
20 | + "devDependencies": { | |
21 | + "@nuxtjs/i18n": "^8.3.1", | |
22 | + "autoprefixer": "^10.4.19", | |
23 | + "postcss": "^8.4.38", | |
24 | + "sass": "^1.77.1", | |
25 | + "tailwindcss": "^3.4.3" | |
26 | + } | |
27 | +} | ... | ... |
pages/about.vue
0 → 100644
1 | +++ a/pages/about.vue | |
1 | +<template> | |
2 | + <v-container class="pa-0 pa-sm-4"> | |
3 | + <div class="my-8 my-sm-16 text-blue-darken-1 text-h4 tw-text-center" v-if="!isMobile()"> | |
4 | + <strong>Company Profile</strong> | |
5 | + </div> | |
6 | + | |
7 | + <v-row class="pb-sm-16 ma-0"> | |
8 | + <v-col cols="12" sm="5" class="pa-0 tw-relative"> | |
9 | + <v-img src="/about_img/1.jpg" alt="canrud"></v-img> | |
10 | + <div | |
11 | + class="py-4 tw-bottom-0 tw-absolute tw-w-full text-h5 tw-text-center tw-bg-[rgba(30,136,229,0.8)] tw-text-white" | |
12 | + v-if="isMobile()"> | |
13 | + <strong>Company Profile</strong> | |
14 | + </div> | |
15 | + </v-col> | |
16 | + <v-col class="tw-leading-8" v-if="!isMobile()"> | |
17 | + <p class="text-grey-darken-1"> | |
18 | + <b>1. </b>2015.2.11 was established in Songshan Lake High-tech Zone; | |
19 | + </p> | |
20 | + <p class="text-grey-darken-1"><b>2.</b> Registered capital of 1000W;</p> | |
21 | + <p class="text-grey-darken-1"> | |
22 | + <b>3.</b> Main business of new energy technology development | |
23 | + </p> | |
24 | + <p class="text-grey-darken-1"> | |
25 | + <b>4.</b> | |
26 | + (Customized/ equipment / testing / materials / new product development, etc.); | |
27 | + </p> | |
28 | + <p class="text-grey-darken-1"> | |
29 | + <b>5.</b> In 2017, it was approved as a national high-tech enterprise; | |
30 | + </p> | |
31 | + <p class="text-grey-darken-1"><b>6.</b> 120+ invention patents; 100 + authorized;</p> | |
32 | + <p class="text-grey-darken-1"> | |
33 | + <b>7.</b> The plant area is 6,000 m 2, with 70 employees (the core team is from Ningde | |
34 | + ATL/ Foxconn). | |
35 | + </p> | |
36 | + </v-col> | |
37 | + <v-col cols="12" class="tw-leading-6 tw-text-white tw-bg-[#1e88e5] px-10 pb-8" v-if="isMobile()"> | |
38 | + <ul> | |
39 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
40 | + 2015.2.11 was established in Songshan Lake High-tech Zone; | |
41 | + </li> | |
42 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
43 | + Registered capital of 1000W; | |
44 | + </li> | |
45 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
46 | + Main business of new energy technology development | |
47 | + </li> | |
48 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
49 | + (Customized/ equipment / testing / materials / new product development, etc.); | |
50 | + </li> | |
51 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
52 | + In 2017, it was approved as a national high-tech enterprise; | |
53 | + </li> | |
54 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
55 | + 120+ invention patents; 100 + authorized; | |
56 | + </li> | |
57 | + <li class="mb-1 tw-border-white tw-border-0 tw-border-b-2 tw-border-solid tw-list-disc"> | |
58 | + The plant area is 6,000 m 2, with 70 employees (the core team is from Ningde ATL/ | |
59 | + Foxconn). | |
60 | + </li> | |
61 | + </ul> | |
62 | + </v-col> | |
63 | + </v-row> | |
64 | + </v-container> | |
65 | + <v-sheet class="py-8 bg-grey-lighten-5 py-sm-16"> | |
66 | + <v-container> | |
67 | + <div class="mb-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
68 | + <strong>Corporate Culture</strong> | |
69 | + </div> | |
70 | + <v-sheet border rounded v-if="!isMobile()"> | |
71 | + <v-row> | |
72 | + <v-col> | |
73 | + <div class="tw-my-[32px] tw-border-0 tw-border-solid tw-border-r-[1px] tw-border-e-blue-300"> | |
74 | + <div class="mb-4 text-center tw-font-medium tw-text-[32px] tw-flex tw-items-center tw-justify-center"> | |
75 | + <img width="36" src="/about_img/2.png" class="mr-4" alt="canrud" /> | |
76 | + Vision | |
77 | + </div> | |
78 | + | |
79 | + <v-card-text> | |
80 | + the world's top one-stop serviceprovider in the field of new energy research | |
81 | + </v-card-text> | |
82 | + </div> | |
83 | + </v-col> | |
84 | + <v-col> | |
85 | + <div class="tw-my-[32px] tw-border-0 tw-border-solid tw-border-r-[1px] tw-border-e-blue-300"> | |
86 | + <div class="mb-4 text-center tw-font-medium tw-text-[36px] tw-flex tw-items-center tw-justify-center"> | |
87 | + <img width="30" src="/about_img/3.png" class="mr-4" alt="canrud" />Mission | |
88 | + </div> | |
89 | + <v-card-text>Build a "industry-university-research" high-speed channel </v-card-text> | |
90 | + </div> | |
91 | + </v-col> | |
92 | + <v-col> | |
93 | + <div class="tw-my-[32px]"> | |
94 | + <div class="mb-4 text-center tw-font-medium tw-text-[36px] tw-flex tw-items-center tw-justify-center"> | |
95 | + <img width="30" src="/about_img/4.png" class="mr-4" alt="canrud" />Values | |
96 | + </div> | |
97 | + <v-card-text>Burn yourself and contribute to the society Scientific</v-card-text> | |
98 | + </div> | |
99 | + </v-col> | |
100 | + </v-row> | |
101 | + </v-sheet> | |
102 | + <div v-if="isMobile()"> | |
103 | + <v-sheet border rounded="lg" class="my-4 tw-border-0 tw-border-solid tw-border-r-[1px] tw-border-e-blue-300"> | |
104 | + <v-row | |
105 | + class="py-2 ma-0 pr-2 tw-bg-[linear-gradient(rgba(215,237,254,0.88),rgba(215,237,254,0.36))] tw-rounded-[8px]"> | |
106 | + <v-col cols="3" class="text-center tw-flex tw-items-center tw-justify-center tw-box-border"> | |
107 | + <img width="48" src="/about_img/2.png" class="tw-m-auto" alt="canrud" /> | |
108 | + </v-col> | |
109 | + <v-col cols="9"> | |
110 | + <div class="font-weight-bold tw-text-[32px] text-h5">Vision</div> | |
111 | + <div class="font-weight-bold text-body-1"> | |
112 | + the world's top one-stop serviceprovider in the field of new energy research | |
113 | + </div> | |
114 | + </v-col> | |
115 | + </v-row> | |
116 | + </v-sheet> | |
117 | + <v-sheet border rounded="lg" class="my-4 tw-border-0 tw-border-solid tw-border-r-[1px] tw-border-e-blue-300"> | |
118 | + <v-row | |
119 | + class="ma-0 py-2 pr-2 tw-bg-[linear-gradient(rgba(203,220,254,0.88),rgba(203,220,254,0.36))] tw-rounded-[8px]"> | |
120 | + <v-col cols="3" class="text-center tw-flex tw-items-center tw-justify-center tw-box-border"> | |
121 | + <img width="48" src="/about_img/3.png" class="tw-m-auto" alt="canrud" /> | |
122 | + </v-col> | |
123 | + <v-col cols="9 tw-h-[120px]"> | |
124 | + <div class="font-weight-bold tw-text-[32px] text-h5">Mission</div> | |
125 | + <div class="font-weight-bold text-body-1"> | |
126 | + Build a "industry-university-research" high-speed channel | |
127 | + </div> | |
128 | + </v-col> | |
129 | + </v-row> | |
130 | + </v-sheet> | |
131 | + <v-sheet border rounded="lg" class="my-4 tw-border-0 tw-border-solid tw-border-r-[1px] tw-border-e-blue-300"> | |
132 | + <v-row | |
133 | + class="py-2 ma-0 tw-bg-[linear-gradient(rgba(212,246,255,0.88),rgba(212,246,255,0.36))] tw-rounded-[8px]"> | |
134 | + <v-col cols="3" class="text-center tw-flex tw-items-center tw-justify-center tw-box-border"> | |
135 | + <img width="48" src="/about_img/4.png" class="tw-m-auto" alt="canrud" /> | |
136 | + </v-col> | |
137 | + <v-col cols="9 tw-h-[120px]"> | |
138 | + <div class="font-weight-bold tw-text-[32px] text-h5">Values</div> | |
139 | + <div class="font-weight-bold text-body-1"> | |
140 | + Burn yourself and contribute to the society Scientific | |
141 | + </div> | |
142 | + </v-col> | |
143 | + </v-row> | |
144 | + </v-sheet> | |
145 | + </div> | |
146 | + </v-container> | |
147 | + </v-sheet> | |
148 | + <v-sheet class="py-8 py-sm-16" :style="isMobile() | |
149 | + ? 'background: url(/mobile/about-bg.png) no-repeat; background-size: 100% 100%' | |
150 | + : 'background: url(/about_img/bg.png) no-repeat; background-size: 100% 100%' | |
151 | + "> | |
152 | + <v-container> | |
153 | + <div class="mb-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
154 | + <strong>Milestone</strong> | |
155 | + </div> | |
156 | + <v-timeline :direction="isMobile() ? 'vertical' : 'horizontal'"> | |
157 | + <v-timeline-item dot-color="indigo-lighten-1" size="16" fill-dot> | |
158 | + <template v-slot:opposite> | |
159 | + <strong class="text-blue-darken-1 tw-text-[22px]">2015</strong></template> | |
160 | + <p class="tw-text-[14px]"> | |
161 | + <strong>Canrd <br /> | |
162 | + established</strong> | |
163 | + </p> | |
164 | + </v-timeline-item> | |
165 | + <v-timeline-item dot-color="blue-darken-1" fill-dot size="32"> | |
166 | + <template v-slot:opposite> | |
167 | + <strong class="text-blue-darken-1 tw-text-[22px]">2017</strong></template> | |
168 | + <div> | |
169 | + <p> | |
170 | + <strong class="tw-text-[14px]">National high-tech <br /> | |
171 | + enterprise</strong> | |
172 | + </p> | |
173 | + </div> | |
174 | + </v-timeline-item> | |
175 | + <v-timeline-item dot-color="indigo-lighten-1" size="16" fill-dot> | |
176 | + <template v-slot:opposite> | |
177 | + <strong class="text-blue-darken-1 tw-text-[22px]">2018</strong> | |
178 | + </template> | |
179 | + <div> | |
180 | + <p class="tw-text-[14px]"><strong>Customers</strong></p> | |
181 | + <p class="tw-text-[14px]"><strong>exceed 2000+</strong></p> | |
182 | + </div> | |
183 | + </v-timeline-item> | |
184 | + <v-timeline-item dot-color="blue-darken-1" fill-dot size="32"> | |
185 | + <template v-slot:opposite> | |
186 | + <strong class="text-blue-darken-1 tw-text-[22px]" fill-dot>2020</strong> | |
187 | + </template> | |
188 | + | |
189 | + <div class="tw-text-[14px]"> | |
190 | + <p><strong>Customized division</strong></p> | |
191 | + <p><strong>Testing division(Xia Men)</strong></p> | |
192 | + </div> | |
193 | + </v-timeline-item> | |
194 | + <v-timeline-item dot-color="indigo-lighten-1" size="16" fill-dot> | |
195 | + <template v-slot:opposite> | |
196 | + <strong class="text-blue-darken-1 tw-text-[22px]">2021</strong> | |
197 | + </template> | |
198 | + <div class="tw-text-[14px]"> | |
199 | + <p><strong>Equipment division</strong></p> | |
200 | + </div> | |
201 | + </v-timeline-item> | |
202 | + <v-timeline-item dot-color="blue-darken-1" fill-dot size="32"> | |
203 | + <template v-slot:opposite> | |
204 | + <strong class="text-blue-darken-1 tw-text-[22px]">2022</strong></template> | |
205 | + | |
206 | + <div class="tw-text-[14px]"> | |
207 | + <p><strong>R&D center(Houjie)</strong></p> | |
208 | + <p><strong>>Pack division</strong></p> | |
209 | + </div> | |
210 | + </v-timeline-item> | |
211 | + </v-timeline> | |
212 | + </v-container> | |
213 | + </v-sheet> | |
214 | + <v-sheet class="bg-grey-lighten-6 pt-8 pt-sm-16 tw-pb-[128px]"> | |
215 | + <v-container> | |
216 | + <div class="mb-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
217 | + <strong>R&D Ability</strong> | |
218 | + </div> | |
219 | + <div class="text-body-1 font-weight-medium tw-mb-[24px] tw-max-w-[600px] tw-m-auto text-grey-darken-1"> | |
220 | + The combination of hardware and software creates strong research and development | |
221 | + capabilities. | |
222 | + </div> | |
223 | + <div class="text-body-1 font-weight-medium tw-mb-[64px] tw-max-w-[600px] tw-m-auto text-grey-darken-1"> | |
224 | + The invention patents cover new materials such as silicon carbon, graphene, lithium sulfur, | |
225 | + sodium electricity and lithium metal, as well as gel process, pre-lithium process and | |
226 | + flexible battery design." | |
227 | + </div> | |
228 | + <v-row> | |
229 | + <v-col cols="12" sm="4"> | |
230 | + <v-card variant="outlined" color="blue-darken-1" v-if="!isMobile()"> | |
231 | + <v-img src="/about_img/5.png" alt="canrud"></v-img> | |
232 | + <v-card-title class="text-grey-darken-4">Team</v-card-title> | |
233 | + <v-card-text class="text-grey-darken-4">Core team members are all from ATL/Foxconn 12+working experience | |
234 | + </v-card-text> | |
235 | + </v-card> | |
236 | + <v-sheet v-if="isMobile()" rounded="lg"> | |
237 | + <v-row class="ma-0"> | |
238 | + <v-col cols="5" sm="12" class="pa-0 tw-rounded-l-lg"> | |
239 | + <img src="/about_img/5.png" alt="canrud" class="tw-w-full tw-h-full tw-rounded-l-lg" /> | |
240 | + </v-col> | |
241 | + <v-col cols="7" class="pa-0 tw-bg-[#1e88e5] tw-rounded-r-lg text-white"> | |
242 | + <v-card-title class="">Team</v-card-title> | |
243 | + <v-card-text>Core team members are all from ATL/Foxconn 12+working experience | |
244 | + </v-card-text> | |
245 | + </v-col> | |
246 | + </v-row> | |
247 | + </v-sheet> | |
248 | + </v-col> | |
249 | + <v-col cols="12" sm="4"> | |
250 | + <v-card variant="outlined" color="blue-darken-1" v-if="!isMobile()"> | |
251 | + <v-img src="/about_img/6.png" alt="canrud"></v-img> | |
252 | + <v-card-title class="text-grey-darken-4">Patents</v-card-title> | |
253 | + <v-card-text class="text-grey-darken-4"> | |
254 | + More than 120 invention patents, covering materials, design, process, equipment and so | |
255 | + on | |
256 | + </v-card-text> | |
257 | + </v-card> | |
258 | + <v-sheet v-if="isMobile()" rounded="lg"> | |
259 | + <v-row class="ma-0"> | |
260 | + <v-col cols="7" class="pa-0 tw-bg-[#1e88e5] tw-rounded-l-lg text-white"> | |
261 | + <v-card-title>Patents</v-card-title> | |
262 | + <v-card-text> | |
263 | + More than 120 invention patents, covering materials, design, process, equipment | |
264 | + and so on | |
265 | + </v-card-text> | |
266 | + </v-col> | |
267 | + <v-col cols="5" sm="12" class="pa-0 tw-rounded-r-lg"> | |
268 | + <img src="/about_img/6.png" alt="canrud" class="tw-w-full tw-h-full tw-rounded-r-lg" /> | |
269 | + </v-col> | |
270 | + </v-row> | |
271 | + </v-sheet> | |
272 | + </v-col> | |
273 | + <v-col cols="12" sm="4"> | |
274 | + <v-card variant="outlined" color="blue-darken-1" v-if="!isMobile()"> | |
275 | + <v-img src="/about_img/7.png" alt="canrud"></v-img> | |
276 | + <v-card-title class="text-grey-darken-4">Hardware</v-card-title> | |
277 | + <v-card-text class="text-grey-darken-4"> | |
278 | + <row>Independent battery pilot line and equipment production line</row> | |
279 | + </v-card-text> | |
280 | + </v-card> | |
281 | + <v-sheet v-if="isMobile()" rounded="lg"> | |
282 | + <v-row class="ma-0"> | |
283 | + <v-col cols="7" class="pa-0 tw-bg-[#1e88e5] tw-rounded-l-lg text-white"> | |
284 | + <v-card-title>Hardware</v-card-title> | |
285 | + <div class="px-4 text-body-1 text-bold"> | |
286 | + Independent battery pilot line and equipment production line | |
287 | + </div> | |
288 | + </v-col> | |
289 | + <v-col cols="5" sm="12" class="pa-0 tw-rounded-r-lg"> | |
290 | + <img src="/about_img/7.png" alt="canrud" class="tw-w-full tw-h-full tw-rounded-r-lg" /> | |
291 | + </v-col> | |
292 | + </v-row> | |
293 | + </v-sheet> | |
294 | + </v-col> | |
295 | + </v-row> | |
296 | + </v-container> | |
297 | + </v-sheet> | |
298 | +</template> | |
299 | + | |
300 | +<script setup lang="ts"> | |
301 | +import MainTitle from '../components/MainTitle.vue' | |
302 | +import { isMobile } from '../utils' | |
303 | + | |
304 | +useHead({ | |
305 | + title: 'About Us', | |
306 | + meta: [ | |
307 | + { | |
308 | + name: 'title', | |
309 | + content: '科路得,canrd,canrud,New energy technology development,National high-tech enterprise,Battery pilot line,Lab Device', | |
310 | + }, { | |
311 | + name: 'keywords', | |
312 | + content: | |
313 | + '科路得,canrd,canrud,New energy technology development,National high-tech enterprise,Battery pilot line,Lab Device', | |
314 | + }, { | |
315 | + name: 'description', | |
316 | + content: | |
317 | + '科路得,助您科研之路势在必得。Canrd aims to be the world‘s leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions.', | |
318 | + }, | |
319 | + ], | |
320 | +}) | |
321 | + | |
322 | +</script> | |
323 | + | |
324 | +<style lang="scss" scoped> | |
325 | +// @use 'vuetify/settings' with ( | |
326 | +// $sheet-border-color: '#1e88e5' | |
327 | +// ); | |
328 | + | |
329 | +b { | |
330 | + display: inline; | |
331 | + font-size: 20px; | |
332 | + color: #1e88e5; | |
333 | + font-style: italic; | |
334 | +} | |
335 | + | |
336 | +p { | |
337 | + cursor: default; | |
338 | + font-weight: bold; | |
339 | +} | |
340 | +</style> | ... | ... |
pages/contact.vue
0 → 100644
1 | +++ a/pages/contact.vue | |
1 | +<template> | |
2 | + <div class="tw-text-center tw-text-4xl tw-mb-[32px] tw-mt-[30px]">Contact Us</div> | |
3 | + <v-card class="pa-10 tw-max-w-[800px] tw-m-auto"> | |
4 | + <h3 class="text-h5 tw-mb-5">Official Web</h3> | |
5 | + <div class="tw-mb-10"> | |
6 | + <label class="text-subtitle-1 tw-mr-4 tw-w-20 tw-inline-block">URL</label> | |
7 | + <span>http://www.canrud.com</span> | |
8 | + </div> | |
9 | + <h3 class="text-h5 tw-mb-5">Technical Center</h3> | |
10 | + <div> | |
11 | + <label class="text-subtitle-1 tw-mr-4 tw-w-20 tw-inline-block">QQ</label> | |
12 | + <span>3632191327</span> | |
13 | + </div> | |
14 | + <div> | |
15 | + <label class="text-subtitle-1 tw-mr-4 tw-w-20 tw-inline-block">Phone</label> | |
16 | + <span>19867737979</span> | |
17 | + </div> | |
18 | + <div > | |
19 | + <label class="text-subtitle-1 tw-mr-4 tw-w-20 tw-inline-block">Email</label> | |
20 | + <span>contact@canrd.com</span> | |
21 | + </div> | |
22 | + <div class="tw-mb-1"> | |
23 | + <label class="text-subtitle-1 tw-mr-4 tw-w-20 tw-inline-block">Wechat</label> | |
24 | + <span>contactcanrd</span> | |
25 | + </div> | |
26 | + <div class="tw-w-[300px]"> | |
27 | + <v-img src="/wechat.jpg"></v-img> | |
28 | + </div> | |
29 | + </v-card> | |
30 | +</template> | |
31 | + | |
32 | +<script setup lang="ts"></script> | |
33 | + | |
34 | +<style lang="less" scoped></style> | ... | ... |
pages/customize.vue
0 → 100644
1 | +++ a/pages/customize.vue | |
1 | +<template> | |
2 | + <v-img src="/banner/customize.jpg" alt="canrud" v-if="!isMobile()"></v-img> | |
3 | + <v-img src="/mobile/banner-custo1.png" alt="canrud" v-if="isMobile()"></v-img> | |
4 | + <div class="font-weight-bold tw-leading-[30px] text-white tw-bg-[url('/banner/top2.png')] tw-p-4 sm:tw-p-8"> | |
5 | + Leading hardware support for customized battery solutions. Independent prototyping line covers | |
6 | + the entire process. Equipped with a soft-pack development line and a -50°C drying room to meet | |
7 | + various needs. Two lithium metal pouch cell preparation options provided. Strong R&D | |
8 | + capabilities with over 10 years of experience. Resolving 100+ customized projects, serving 50+ | |
9 | + clients. Services include material evaluation, R&D contract manufacturing, new system | |
10 | + development, and finished/semi-finished products. Breakthroughs in high-temperature, | |
11 | + low-temperature, and fast-charging fields. Production and sales of high-quality lithium-ion | |
12 | + batteries. Choose us to meet your R&D and production needs. | |
13 | + </div> | |
14 | + <div class="tw-p-[32px] sm:tw-pt-[64px] sm:tw-px-[128px]"> | |
15 | + <div class="mb-4 mb-sm-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
16 | + <b>Customization Hardware</b> | |
17 | + </div> | |
18 | + <v-divider class="mb-8 mb-sm-16"></v-divider> | |
19 | + <ContentDescription className=" mb-4 mb-sm-16 tw-max-w-[600px] tw-m-auto font-weight-medium text-grey-darken-1" | |
20 | + content="Coin cell preparation line with different machine such as mixing, coating, calendaring, | |
21 | + cutting, assembly and testing." /> | |
22 | + <v-container class="px-0 px-sm-16"> | |
23 | + <v-row class="tw-justify-between"> | |
24 | + <v-col cols="6" sm="5"> | |
25 | + <v-img src="/customization_hardware/1.png" alt="canrud"></v-img> | |
26 | + </v-col> | |
27 | + <v-col cols="6" sm="5"> | |
28 | + <v-img src="/customization_hardware/2.png" alt="canrud"></v-img> | |
29 | + </v-col> | |
30 | + </v-row> | |
31 | + </v-container> | |
32 | + <v-divider class="my-8 my-sm-16"></v-divider> | |
33 | + <div class="tw-max-w-[600px] tw-m-auto font-weight-medium tw-mb-[32px] text-grey-darken-1"> | |
34 | + <div>1、Pouch cell pilot line with different humidity control requirement</div> | |
35 | + <div>2、Dry room for other process</div> | |
36 | + <div>3、Dry room for mixing and coating with -30℃ humidity</div> | |
37 | + <div>4、(before electrolyte injection)with -40℃ humidity</div> | |
38 | + </div> | |
39 | + <!-- <v-slide-group class="pa-4" selected-class="bg-success" show-arrows> | |
40 | + <v-slide-group-item v-for="slide in slides" :key="slide"> | |
41 | + <v-card :class="['ma-2']" width="360"> | |
42 | + <v-img :src="slide"></v-img> | |
43 | + </v-card> | |
44 | + </v-slide-group-item> | |
45 | + </v-slide-group> --> | |
46 | + <v-row v-if="!isMobile()"> | |
47 | + <v-col v-for="slide in slides" :key="slide"><v-img :src="slide" alt="canrud"></v-img></v-col> | |
48 | + </v-row> | |
49 | + | |
50 | + <v-carousel height="298" width="318" interval="3000" cycle :continuous="false" :show-arrows="false" | |
51 | + hide-delimiter-background v-if="isMobile()"> | |
52 | + <v-carousel-item v-for="n in slides" :key="n"> | |
53 | + <v-sheet color="grey-lighten-1" height="298" width="318" class="mx-auto" border="none"> | |
54 | + <!-- <v-card-title class="tw-text-center text-subtitle-1">{{ n.name }}</v-card-title> --> | |
55 | + <v-img :src="n" alt="canrud"></v-img> | |
56 | + </v-sheet> | |
57 | + </v-carousel-item> | |
58 | + </v-carousel> | |
59 | + | |
60 | + <v-divider class="my-8 my-sm-16"></v-divider> | |
61 | + <div class="tw-max-w-[600px] tw-m-auto font-weight-medium tw-mb-[32px] text-grey-darken-1"> | |
62 | + <div>1、There are different capacity for mixing(5L,10L and 30L)</div> | |
63 | + <div>2、Dry room for high Ni cathode pouch cell preparation(-30℃ humidity)</div> | |
64 | + <div> | |
65 | + 3、Different solution to prepare lithium metal pouch cell(glove box with 0.1ppm condition or | |
66 | + -50℃ dry room) | |
67 | + </div> | |
68 | + </div> | |
69 | + | |
70 | + <v-row v-if="!isMobile()"> | |
71 | + <v-col v-for="img in imgs" :key="img.name"> | |
72 | + <v-card> | |
73 | + <v-img :src="img.imageUrl" alt="canrud"></v-img> | |
74 | + <v-card-title class="tw-text-center text-subtitle-1">{{ img.name }}</v-card-title> | |
75 | + </v-card> | |
76 | + </v-col> | |
77 | + </v-row> | |
78 | + | |
79 | + <v-carousel height="350" width="318" interval="3000" cycle :continuous="false" :show-arrows="false" | |
80 | + hide-delimiter-background v-if="isMobile()"> | |
81 | + <v-carousel-item v-for="n in imgs" :key="n.imageUrl"> | |
82 | + <v-sheet color="grey-lighten-1" height="340" width="318" class="mx-auto" border="none"> | |
83 | + <v-card-title class="tw-text-center text-subtitle-1">{{ n.name }}</v-card-title> | |
84 | + <v-img :src="n.imageUrl" alt="canrud"></v-img> | |
85 | + </v-sheet> | |
86 | + </v-carousel-item> | |
87 | + </v-carousel> | |
88 | + </div> | |
89 | + | |
90 | + <div class="tw-p-[32px] sm:tw-py-[64px] sm:tw-px-[128px] bg-grey-lighten-5"> | |
91 | + <div class="mb-4 mb-sm-16 text-blue-darken-1 text-h5 text-sm-h4 tw-text-center"> | |
92 | + <b>Succeed Case</b> | |
93 | + </div> | |
94 | + <div class="mb-8 tw-relative mb-sm-16"> | |
95 | + <div | |
96 | + class="tw-w-[200px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-text-[20px] tw-font-medium tw-relative"> | |
97 | + customized types | |
98 | + </div> | |
99 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
100 | + </div> | |
101 | + | |
102 | + <v-row class="mb-8 px-sm-16 tw-justify-between mb-sm-16 tw-flex"> | |
103 | + <v-col v-for="slide in slideCases" :key="slide.title" cols="6" sm="5"> | |
104 | + <!-- <v-card> --> | |
105 | + <v-img :src="slide.imageUrl" :alt="slide.title"></v-img> | |
106 | + <v-card-title class="tw-text-center text-subtitle-1"> {{ slide.title }}</v-card-title> | |
107 | + <!-- </v-card> --> | |
108 | + </v-col> | |
109 | + </v-row> | |
110 | + | |
111 | + <!-- <v-slide-group class="pa-4" selected-class="bg-success" show-arrows> | |
112 | + <v-slide-group-item v-for="slide in slideCases" :key="slide"> | |
113 | + <v-card :class="['ma-2']" width="360"> | |
114 | + <v-img :src="slide"></v-img> | |
115 | + </v-card> | |
116 | + </v-slide-group-item> | |
117 | + </v-slide-group> --> | |
118 | + | |
119 | + <div class="pb-8 tw-relative pb-sm-16"> | |
120 | + <div | |
121 | + class="mb-8 mb-sm-16 tw-w-[210px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-text-[20px] tw-font-medium tw-relative"> | |
122 | + Material evaluation | |
123 | + </div> | |
124 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
125 | + | |
126 | + <ContentDescription className="mb-8 mb-sm-16 tw-max-w-[600px] tw-m-auto font-weight-medium text-grey-darken-1" | |
127 | + content="Comprehensive lithium battery material evaluation, covering key materials such as cathode, anode, electrolyte, separator, and conductive additives. Accurate testing to ensure high-performance batteries. Choose us to embark on the path of material innovation!." /> | |
128 | + | |
129 | + <v-img src="/customization_case/table.png" alt="canrud"></v-img> | |
130 | + </div> | |
131 | + <!-- <v-table density="compact" class="mb-8 mb-sm-16"> | |
132 | + <thead> | |
133 | + <tr class="bg-blue-lighten-1"> | |
134 | + <th class="text-left text-white">Cathode</th> | |
135 | + <th class="text-left text-white">Anode</th> | |
136 | + <th class="text-left text-white">Electrolyte</th> | |
137 | + <th class="text-left text-white">Separator</th> | |
138 | + <th class="text-left text-white">Conductive carbon</th> | |
139 | + </tr> | |
140 | + </thead> | |
141 | + <tbody> | |
142 | + <tr class="bg-light-blue-lighten-5"> | |
143 | + <td>1</td> | |
144 | + <td>2</td> | |
145 | + <td>1</td> | |
146 | + <td>2</td> | |
147 | + <td>1</td> | |
148 | + </tr> | |
149 | + <tr class="bg-light-blue-lighten-5"> | |
150 | + <td>1</td> | |
151 | + <td>2</td> | |
152 | + <td>2</td> | |
153 | + <td>2</td> | |
154 | + <td>2</td> | |
155 | + </tr> | |
156 | + </tbody> | |
157 | + </v-table> --> | |
158 | + | |
159 | + <div class="mb-8 tw-relative mb-sm-16"> | |
160 | + <div | |
161 | + class="tw-w-[220px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-text-[20px] tw-font-medium tw-relative"> | |
162 | + System development | |
163 | + </div> | |
164 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
165 | + </div> | |
166 | + | |
167 | + <ContentDescription className="mb-8 mb-sm-16 tw-max-w-[600px] tw-m-auto font-weight-medium text-grey-darken-1" | |
168 | + content="High temperature: mine safety helmet Low temperature: outdoor extreme cold applicationFast charging system development: fast charging power bank Water system battery development: new system development." /> | |
169 | + | |
170 | + <v-row class="mb-16"> | |
171 | + <!-- <v-col v-for="slide in slideCases" :key="slide"><v-img :src="slide"></v-img></v-col> --> | |
172 | + <v-img src="/customization_case/b.png" alt="canrud"></v-img> | |
173 | + </v-row> | |
174 | + </div> | |
175 | +</template> | |
176 | + | |
177 | +<script setup lang="ts"> | |
178 | +import ContentDescription from '@/components/ContentDescription.vue' | |
179 | +import { isMobile } from '~/utils' | |
180 | + | |
181 | +useHead({ | |
182 | + title: 'About Us', | |
183 | + meta: [ | |
184 | + { | |
185 | + name: 'title', | |
186 | + content: | |
187 | + '科路得,Hardware support,Customized battery solutions,Prototyping line,Soft-pack development line,Lithium metal pouch cell,R&D capabilities,Material evaluation,R&D contract manufacturing,High-temperature,Lithium-ion batteries', | |
188 | + }, { | |
189 | + name: 'keywords', | |
190 | + content: | |
191 | + '科路得,Hardware support,Customized battery solutions,Prototyping line,Soft-pack development line,Lithium metal pouch cell,R&D capabilities,Material evaluation,R&D contract manufacturing,High-temperature,Lithium-ion batteries', | |
192 | + }, { | |
193 | + name: 'description', | |
194 | + content: | |
195 | + '科路得,助您科研之路势在必得。Leading hardware support for customized battery solutions. Independent prototyping line covers the entire process. Equipped with a soft-pack development line and a -50°C drying room to meet various needs. Two lithium metal pouch cell preparation options provided. Strong R&D capabilities with over 10 years of experience. Resolving 100+ customized projects, serving 50+ clients. Services include material evaluation, R&D contract manufacturing, new system development, and finished/semi-finished products. Breakthroughs in high-temperature, low-temperature, and fast-charging fields. Production and sales of high-quality lithium-ion batteries. Choose us to meet your R&D and production needs.' | |
196 | + }, | |
197 | + ], | |
198 | +}) | |
199 | + | |
200 | +const slides = [ | |
201 | + '/customization_hardware/3.png', | |
202 | + '/customization_hardware/4.png', | |
203 | + '/customization_hardware/5.png', | |
204 | + '/customization_hardware/6.png' | |
205 | +] | |
206 | + | |
207 | +const slideCases = [ | |
208 | + { imageUrl: '/customization_case/1.png', title: '1.Semi-finished product' }, | |
209 | + { imageUrl: '/customization_case/2.png', title: 'Material evaluation' }, | |
210 | + { imageUrl: '/customization_case/3.png', title: 'System development' }, | |
211 | + { imageUrl: '/customization_case/4.png', title: 'New product customization' } | |
212 | + // '/customization_case/5.png' | |
213 | +] | |
214 | + | |
215 | +const imgs = [ | |
216 | + { name: '5L mixing', imageUrl: '/customization_hardware/9.png' }, | |
217 | + { name: '30L mixing', imageUrl: '/customization_hardware/10.png' }, | |
218 | + { name: 'Li metal pouch cell', imageUrl: '/customization_hardware/11.png' } | |
219 | +] | |
220 | +</script> | |
221 | + | |
222 | +<style lang="less" scoped></style> | ... | ... |
pages/equipment.vue
0 → 100644
1 | +++ a/pages/equipment.vue | |
1 | +<template> | |
2 | + <v-img src="/banner/equipment.jpg" alt="canrud" v-if="!isMobile()"></v-img> | |
3 | + <v-img src="/mobile/banner-equipment.png" alt="canrud" v-if="isMobile()"></v-img> | |
4 | + <div class="font-weight-bold tw-leading-[30px] text-white tw-bg-[url('/banner/top2.png')] tw-p-4 sm:tw-p-8"> | |
5 | + Equipment Business: With our self-built high-precision machining center, we possess robust | |
6 | + design and manufacturing capabilities. We offer comprehensive equipment supply, production line | |
7 | + planning, and construction services, including battery assembly lines, pouch cell testing lines, | |
8 | + and more. Our aim is to provide complete equipment solutions that cater to the diverse needs of | |
9 | + our clients. Expect top-quality equipment and professional services that will help you stand out | |
10 | + in a fiercely competitive market! | |
11 | + </div> | |
12 | + | |
13 | + <div class="tw-p-[32px] sm:tw-pt-[64px] sm:tw-px-[128px]"> | |
14 | + <div class="mb-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
15 | + <b>Equipment hardware</b> | |
16 | + </div> | |
17 | + <v-row> | |
18 | + <v-col cols="12"> | |
19 | + <v-slide-group class="pa-4 mb-sm-8 tw-w-[110%] tw-ml-[-5%]" center-active show-arrows v-model="equipSlide" | |
20 | + v-if="screenWidth > 600"> | |
21 | + <v-slide-group-item v-for="n in equipments" :key="n.name"> | |
22 | + <v-card :class="['ma-4']" width="280"> | |
23 | + <v-img width="256" :src="n.imageUrl" class="ma-2" :alt="n.name"></v-img> | |
24 | + <v-card-title class="tw-text-center text-subtitle-1">{{ n.name }}</v-card-title> | |
25 | + </v-card> | |
26 | + </v-slide-group-item> | |
27 | + </v-slide-group> | |
28 | + | |
29 | + <v-carousel height="350" width="318" interval="3000" cycle :continuous="false" :show-arrows="false" | |
30 | + hide-delimiter-background v-if="isMobile()"> | |
31 | + <v-carousel-item v-for="n in equipments" :key="n.imageUrl"> | |
32 | + <v-sheet color="grey-lighten-1" height="350" width="318" class="mx-auto" border="none"> | |
33 | + <v-card-title class="tw-text-center text-subtitle-1">{{ n.name }}</v-card-title> | |
34 | + <v-img :src="n.imageUrl" alt="canrud"></v-img> | |
35 | + </v-sheet> | |
36 | + </v-carousel-item> | |
37 | + </v-carousel> | |
38 | + </v-col> | |
39 | + </v-row> | |
40 | + </div> | |
41 | + <div class="tw-p-[32px] sm:tw-py-[64px] sm:tw-px-[128px] bg-grey-lighten-5"> | |
42 | + <div class="mb-4 mb-sm-16 text-blue-darken-1 text-h5 text-sm-h4 tw-text-center"> | |
43 | + <b>Succeed Case</b> | |
44 | + </div> | |
45 | + | |
46 | + <div class="mb-sm-16 tw-relative"> | |
47 | + <div | |
48 | + class="bg-blue-darken-1 text-subtitle-1 text-md-h6 tw-w-[140px] tw-rounded-[4px] tw-m-auto tw-text-center tw-relative"> | |
49 | + Coin cell | |
50 | + </div> | |
51 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
52 | + </div> | |
53 | + <v-row class="mb-8 mb-sm-16"> | |
54 | + <v-col cols="12" sm="6"> | |
55 | + <v-img class="text-white align-end" src="/succeed_case/device-Coin cell Line.png" cover | |
56 | + alt="device-Coin cell Line" /> | |
57 | + </v-col> | |
58 | + <v-col cols="12" sm="6"> | |
59 | + <div | |
60 | + class="font-weight-medium text-body-1 tw-text-justify tw-h-full tw-items-center tw-flex text-grey-darken-1"> | |
61 | + Our coin cell production line comprises a well-established process that includes material | |
62 | + baking, vacuum mixing, slurry filtration, electrode coating, electrode drying, electrode | |
63 | + rolling, punching, environmental control, cell assembly, cell sealing, and formation | |
64 | + testing. Through precise operations and advanced technology, we ensure uniform coating of | |
65 | + positive and negative electrode materials, precise dimensions, and optimal performance. | |
66 | + Our production line strictly adheres to quality standards, guaranteeing reliable | |
67 | + manufacturing of pouch cells. From material preparation to final testing, our professional | |
68 | + production line ensures outstanding performance and reliable safety, meeting the diverse | |
69 | + needs of our customers. | |
70 | + </div> | |
71 | + </v-col> | |
72 | + </v-row> | |
73 | + | |
74 | + <div class="mb-8 mb-sm-16 tw-relative"> | |
75 | + <div | |
76 | + class="bg-blue-darken-1 text-subtitle-1 text-md-h6 tw-w-[210px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-relative"> | |
77 | + Pouch cell pilot line | |
78 | + </div> | |
79 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
80 | + </div> | |
81 | + <v-row class="mb-8 mb-sm-16"> | |
82 | + <v-col cols="12" sm="6"> | |
83 | + <div | |
84 | + class="font-weight-medium text-body-1 tw-text-justify tw-h-full tw-items-center tw-flex text-grey-darken-1"> | |
85 | + Our pouch cell pilot line is a highly specialized production line that encompasses key | |
86 | + processes such as vacuum mixing, electrode coating, electrode rolling, electrode cutting, | |
87 | + electrode stacking, electrode welding, film forming, top-side sealing, electrolyte | |
88 | + filling, vacuum resting, vacuum sealing, hot pressing formation, vacuum final sealing, and | |
89 | + pouch cell assembly. Through meticulous operations and advanced technology, we ensure the | |
90 | + consistency and reliability of the positive and negative electrodes. Each step is | |
91 | + carefully controlled to guarantee the stability, reliability, and high performance of the | |
92 | + cells. Our pouch cell pilot line meets industry standards and caters to the professional | |
93 | + needs of our customers. Whether for research samples or small-scale production, we provide | |
94 | + high-quality and highly reliable pouch cell products. | |
95 | + </div> | |
96 | + </v-col> | |
97 | + <v-col cols="12" sm="6"> | |
98 | + <v-img class="text-white align-end" src="/succeed_case/device-pouch.png" cover alt="device-pouch" /> | |
99 | + </v-col> | |
100 | + </v-row> | |
101 | + | |
102 | + <div class="mb-8 mb-sm-16 tw-relative"> | |
103 | + <div | |
104 | + class="bg-blue-darken-1 text-subtitle-1 text-md-h6 tw-w-[300px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-relative"> | |
105 | + Pouch cell pilot line (200m2) | |
106 | + </div> | |
107 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
108 | + </div> | |
109 | + <div class="text-h4 tw-text-center text-light-blue-darken-2 tw-mb-[32px]"></div> | |
110 | + <v-row class="mb-8 sm:mb-16"> | |
111 | + <v-col cols="12" sm="6"> | |
112 | + <v-img class="text-white align-end" src="/succeed_case/Pouch cell pilot line (200m2).png" cover | |
113 | + alt="Pouch cell pilot line (200m2)" /> | |
114 | + </v-col> | |
115 | + <v-col cols="12" sm="6"> | |
116 | + <div | |
117 | + class="font-weight-medium text-body-1 tw-text-justify tw-h-full tw-items-center tw-flex text-grey-darken-1"> | |
118 | + Our pouch cell pilot line layout has been meticulously designed, as shown in the | |
119 | + accompanying diagram, to optimize space utilization, streamline workflow, and control | |
120 | + temperature and humidity. This layout ensures high production efficiency, convenient | |
121 | + operation, and precise experimental control. The equipment placement is strategically | |
122 | + arranged, allowing easy access for operators while prioritizing safety considerations. | |
123 | + </div> | |
124 | + </v-col> | |
125 | + </v-row> | |
126 | + | |
127 | + <v-row class="mb-16"> | |
128 | + <v-col cols="12"> | |
129 | + <v-slide-group selected-class="bg-primary" show-arrows v-model="pouchSlide" v-if="screenWidth > 600"> | |
130 | + <v-slide-group-item v-for="img in successCases" :key="img"> | |
131 | + <v-card color="grey-lighten-1" :class="['ma-4']" width="260"> | |
132 | + <v-img :src="img" alt="canrud"></v-img> | |
133 | + </v-card> | |
134 | + </v-slide-group-item> | |
135 | + </v-slide-group> | |
136 | + | |
137 | + <v-carousel height="242" width="318" interval="3000" cycle :continuous="false" :show-arrows="false" | |
138 | + hide-delimiter-background v-if="screenWidth <= 600"> | |
139 | + <v-carousel-item v-for="img in successCases" :key="img"> | |
140 | + <v-card color="grey-lighten-1" :class="['ma-4']"> | |
141 | + <v-img :src="img" alt="canrud"></v-img> | |
142 | + </v-card> | |
143 | + </v-carousel-item> | |
144 | + </v-carousel> | |
145 | + </v-col> | |
146 | + </v-row> | |
147 | + | |
148 | + <div class="mb-8 tw-relative mb-sm-16"> | |
149 | + <div | |
150 | + class="bg-blue-darken-1 text-subtitle-1 text-md-h6 tw-w-[210px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-relative"> | |
151 | + Pouch cell pilot line | |
152 | + </div> | |
153 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
154 | + </div> | |
155 | + <v-container> | |
156 | + <v-row> | |
157 | + <v-col cols="6"> | |
158 | + <v-img :src="fixtures[0].imageUrl" alt="Customized fixture"></v-img> | |
159 | + <!-- <div | |
160 | + class="tw-mt-[16px] font-weight-medium text-body-1 tw-text-center text-grey-darken-1" | |
161 | + > | |
162 | + Real-time monitor and record the pressure during test; Limit pressure: 1960N; | |
163 | + Accuracy: 0.05%; Operating temperature: -20℃ ~70℃ | |
164 | + </div> --> | |
165 | + <div class="tw-mt-[16px] font-weight-medium text-body-1 tw-text-center text-grey-darken-1"> | |
166 | + Customized fixture | |
167 | + </div> | |
168 | + </v-col> | |
169 | + <v-col cols="6"> | |
170 | + <v-img :src="fixtures[1].imageUrl" alt="Fuel cell test fixture"></v-img> | |
171 | + <div class="tw-mt-[16px] font-weight-medium text-body-1 tw-text-center text-grey-darken-1"> | |
172 | + Fuel cell test fixture | |
173 | + </div> | |
174 | + </v-col> | |
175 | + | |
176 | + <v-col cols="6"> | |
177 | + <v-img :src="fixtures[2].imageUrl" alt="Coin cell"></v-img> | |
178 | + <div class="tw-mt-[16px] font-weight-medium text-body-1 tw-text-center text-grey-darken-1"> | |
179 | + Coin cell | |
180 | + </div> | |
181 | + </v-col> | |
182 | + <v-col cols="6"> | |
183 | + <v-img :src="fixtures[3].imageUrl" alt="Flow battery test fixture"></v-img> | |
184 | + <div class="tw-mt-[16px] font-weight-medium text-body-1 tw-text-center text-grey-darken-1"> | |
185 | + Flow battery test fixture | |
186 | + </div> | |
187 | + </v-col> | |
188 | + </v-row> | |
189 | + </v-container> | |
190 | + </div> | |
191 | +</template> | |
192 | + | |
193 | +<script setup lang="ts"> | |
194 | +import { ref, onMounted, onUnmounted } from 'vue' | |
195 | +import { useDisplay } from 'vuetify' | |
196 | +import { isMobile } from '~/utils' | |
197 | + | |
198 | +const { width: screenWidth } = useDisplay() | |
199 | + | |
200 | +const equipSlide = ref(1) | |
201 | +const pouchSlide = ref(1) | |
202 | +let equipTimer: any = null | |
203 | +let pouchTimer: any = null | |
204 | + | |
205 | +useHead({ | |
206 | + title: 'About Us', | |
207 | + meta: [ | |
208 | + { | |
209 | + name: 'title', | |
210 | + content: | |
211 | + '科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines', | |
212 | + }, { | |
213 | + name: 'keywords', | |
214 | + content: | |
215 | + '科路得,Equipment,High-precision,Machining center,Design,Manufacturing capabilities,Equipment supply,Production line planning,Construction services,Battery assembly lines,Pouch cell testing lines', | |
216 | + }, { | |
217 | + name: 'description', | |
218 | + content: | |
219 | + '科路得,助您科研之路势在必得。Equipment Business: With our self-built high-precision machining center, we possess robust design and manufacturing capabilities. We offer comprehensive equipment supply, production line planning, and construction services, including battery assembly lines, pouch cell testing lines, and more. Our aim is to provide complete equipment solutions that cater to the diverse needs of our clients. Expect top-quality equipment and professional services that will help you stand out in a fiercely competitive market!' | |
220 | + }, | |
221 | + ], | |
222 | +}) | |
223 | + | |
224 | +onMounted(() => { | |
225 | + equipTimer = setInterval(() => { | |
226 | + if (equipSlide.value > equipments.length) { | |
227 | + equipSlide.value = 0 | |
228 | + } else { | |
229 | + equipSlide.value = equipSlide.value + 1 | |
230 | + } | |
231 | + }, 2000) | |
232 | + | |
233 | + pouchTimer = setInterval(() => { | |
234 | + if (pouchSlide.value > successCases.length) { | |
235 | + pouchSlide.value = 0 | |
236 | + } else { | |
237 | + pouchSlide.value = pouchSlide.value + 1 | |
238 | + } | |
239 | + }, 2000) | |
240 | +}) | |
241 | + | |
242 | +onUnmounted(() => { | |
243 | + clearInterval(equipTimer) | |
244 | + clearInterval(pouchTimer) | |
245 | + equipTimer = null | |
246 | + pouchTimer = null | |
247 | +}) | |
248 | + | |
249 | +const equipments = [ | |
250 | + { name: 'Precision grinder', imageUrl: '/lab/precision-grinder.png' }, | |
251 | + { name: 'Numerical control machine', imageUrl: '/lab/numerical-control-machine.png' }, | |
252 | + { name: 'Arm brace', imageUrl: '/lab/arm-brace.png' }, | |
253 | + { | |
254 | + name: 'CNC high-speed precision carving machine', | |
255 | + imageUrl: '/lab/cnc-high-speed-precision-carving-machine.png' | |
256 | + }, | |
257 | + { | |
258 | + name: 'Equipment assembly workshop', | |
259 | + imageUrl: '/lab/equipment-assembly-workshop1.png' | |
260 | + }, | |
261 | + { | |
262 | + name: 'Equipment to be shipped', | |
263 | + imageUrl: '/lab/equipment-to-be-shipped1.png' | |
264 | + }, | |
265 | + { | |
266 | + name: 'Equipment to be shipped', | |
267 | + imageUrl: '/lab/equipment-assembly-workshop2.png' | |
268 | + } | |
269 | +] | |
270 | + | |
271 | +const successCases = [ | |
272 | + '/succeed_case/device1.png', | |
273 | + '/succeed_case/device2.png', | |
274 | + '/succeed_case/device3.png', | |
275 | + '/succeed_case/device4.png', | |
276 | + '/succeed_case/device5.png' | |
277 | +] | |
278 | + | |
279 | +const fixtures = [ | |
280 | + { imageUrl: '/succeed_case/customized_fixture/customized-fixture.png' }, | |
281 | + { imageUrl: '/succeed_case/customized_fixture/fuel-cell-test-fixture.png' }, | |
282 | + { imageUrl: '/succeed_case/customized_fixture/coin-cell.png' }, | |
283 | + { imageUrl: '/succeed_case/customized_fixture/flow-battery-test-fixture.png' } | |
284 | +] | |
285 | +</script> | |
286 | + | |
287 | +<style lang="scss"> | |
288 | +b { | |
289 | + margin-bottom: 0; | |
290 | +} | |
291 | +</style> | ... | ... |
pages/index.vue
0 → 100644
1 | +++ a/pages/index.vue | |
1 | +<template> | |
2 | + <v-rows class="tw-w-full"> | |
3 | + <v-carousel hide-delimiter-background show-arrows="hover" height="auto" v-if="!isMobile()"> | |
4 | + <v-carousel-item v-for="banner in banners" :src="banner" cover alt="canrud" :key="banner"> | |
5 | + </v-carousel-item> | |
6 | + </v-carousel> | |
7 | + <v-carousel hide-delimiter-background show-arrows="hover" height="auto" v-if="isMobile()"> | |
8 | + <v-carousel-item v-for="banner in mobileBanners" :src="banner" cover alt="canrud" :key="banner"> | |
9 | + </v-carousel-item> | |
10 | + </v-carousel> | |
11 | + </v-rows> | |
12 | + <!-- 能源材料 --> | |
13 | + <div class="tw-py-8 py-sm-16"> | |
14 | + <v-container> | |
15 | + <MainTitleListOdd title="Material Reagents" :list="materials" | |
16 | + desc="Leading global provider of energy storage research materials and providing other professional/universal experimental materials. " /> | |
17 | + </v-container> | |
18 | + </div> | |
19 | + | |
20 | + <!-- 设备 --> | |
21 | + <div class="bg-grey-lighten-5 tw-py-8 py-sm-16"> | |
22 | + <v-container> | |
23 | + <MainTitleList title="Lab Device" listType="equipment" | |
24 | + :list="lab.list.map((item) => ({ ...item, href: '/products' }))" | |
25 | + desc="Self-built High-precision Machining Center with Powerful Design and Manufacturing Capabilities. " | |
26 | + href="/equipment" /> | |
27 | + </v-container> | |
28 | + </div> | |
29 | + | |
30 | + <!-- Customized Battery --> | |
31 | + <div class="tw-py-8 py-sm-16"> | |
32 | + <v-container> | |
33 | + <MainTitleList :title="('Customized Battery')" :list="batteries" href="/customize" | |
34 | + desc="200mAh~10Ah, Winding/Stacking, Unfilled/Filled Electrolyte Cells, Three-Electrode, and More. " /> | |
35 | + </v-container> | |
36 | + </div> | |
37 | + <!-- Testing --> | |
38 | + <div class="bg-grey-lighten-5 tw-py-8 py-sm-16"> | |
39 | + <v-container> | |
40 | + <MainTitleList title="Testing" :list="tests" href="/test" | |
41 | + desc="Self built testing center and signed strategic cooperation with ATL, Tsinghua and other units. " /> | |
42 | + </v-container> | |
43 | + </div> | |
44 | + <!-- Pack --> | |
45 | + <div class="pt-8 pb-8 pt pt-sm-16 pb-sm-32"> | |
46 | + <v-container> | |
47 | + <MainTitleList title="Pack" href="/pack" :list="packs" | |
48 | + desc="Focusing on energy materials/new energy storage systems/modules and other fields, mastering advanced technologies to provide high-quality services. " /> | |
49 | + </v-container> | |
50 | + </div> | |
51 | +</template> | |
52 | + | |
53 | +<script setup lang="ts"> | |
54 | +import MainTitleList from '../components/MainTitleList.vue' | |
55 | +import MainTitleListOdd from '../components/MainTitleListOdd.vue' | |
56 | +import { useCategoryStore } from '../stores/category' | |
57 | +import { computed } from 'vue' | |
58 | +import { isMobile } from '../utils' | |
59 | +onMounted(()=>{ | |
60 | + console.log('%c [ onMounted ]-10', 'font-size:13px; background:pink; color:#bf2c9f;',111) | |
61 | +}) | |
62 | +useHead({ | |
63 | + title: 'canrud', | |
64 | + meta: [ | |
65 | + { | |
66 | + name: 'title', | |
67 | + content: "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!" | |
68 | + },{ | |
69 | + name: 'keywords', | |
70 | + content: | |
71 | + '科路得,canrd,canrud,Energy Storage Research,Lithium Batteries Research,Material Reagents,Lab Device,Customized Battery,Testing,Pack', | |
72 | + },{ | |
73 | + name:"description", | |
74 | + content: | |
75 | + "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!" | |
76 | + }] | |
77 | +}) | |
78 | + | |
79 | +// useAsyncData(async ({ app }) => { | |
80 | +// console.log('%c [ app ]-70', 'font-size:13px; background:pink; color:#bf2c9f;', app) | |
81 | +// app.head.title = 'canrud' | |
82 | +// app.head.meta = [ | |
83 | +// { | |
84 | +// name: 'description', | |
85 | +// content: "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at | |
86 | +// }] | |
87 | +// }) | |
88 | +console.log(11) | |
89 | + | |
90 | +const store = useCategoryStore() | |
91 | + | |
92 | +const lab = computed( | |
93 | + () => | |
94 | + store?.list?.[3] || { | |
95 | + categoryDisplayName: '', | |
96 | + list: [] | |
97 | + } | |
98 | +) | |
99 | + | |
100 | +const banners = [ | |
101 | + '/banner/banner1.jpg', | |
102 | + '/banner/banner2.jpg', | |
103 | + '/banner/banner3.jpg', | |
104 | + '/banner/banner4.png' | |
105 | +] | |
106 | + | |
107 | +const mobileBanners = [ | |
108 | + '/mobile/banner-index1.png', | |
109 | + '/mobile/banner-index2.png', | |
110 | + '/mobile/banner-index3.png' | |
111 | +] | |
112 | + | |
113 | +const materials = [ | |
114 | + { name: 'Energy materials', imageUrl: '/home/1.jpg', href: '/products' }, | |
115 | + { | |
116 | + name: 'Laboratory consumables', | |
117 | + imageUrl: '/home/2-Universal-consumables.png', | |
118 | + href: '/products' | |
119 | + }, | |
120 | + { | |
121 | + name: 'Low-dimensional materials', | |
122 | + imageUrl: '/home/3-Low-dimensional-materials.png', | |
123 | + href: '/products' | |
124 | + } | |
125 | +] | |
126 | + | |
127 | +const tests = [ | |
128 | + { | |
129 | + name: 'Electrochemical performance', | |
130 | + imageUrl: '/home/8_Electrochemical_performance.svg', | |
131 | + href: '/test' | |
132 | + }, | |
133 | + { name: 'Reliability testing', imageUrl: '/home/9 Reliability testing.svg', href: '/test' }, | |
134 | + { name: 'Material testing', imageUrl: '/home/10 Material testing.svg', href: '/test' }, | |
135 | + { name: 'Calibration', imageUrl: '/home/11 Calibration.svg', href: '/test' } | |
136 | +] | |
137 | +const batteries = [ | |
138 | + { name: 'Material evaluation', imageUrl: '/home/4-Material-evaluation.png', href: '/customize' }, | |
139 | + { name: 'R&D foundry', imageUrl: '/home/5-R&D-foundry.png', href: '/customize' }, | |
140 | + { name: 'Chemical system', imageUrl: '/home/6-Chemical-system.png', href: '/customize' }, | |
141 | + { | |
142 | + name: 'Semi product customization', | |
143 | + imageUrl: '/home/7-Semi-product-customization.png', | |
144 | + href: '/customize' | |
145 | + } | |
146 | +] | |
147 | +const packs = [ | |
148 | + { name: 'Power bank', imageUrl: '/home/12-power-bank.png', href: '/pack' }, | |
149 | + { name: 'Energy storage', imageUrl: '/home/13-Energy-storage.png', href: '/pack' }, | |
150 | + { name: 'power tool', imageUrl: '/home/3-powertool.png', href: '/pack' }, | |
151 | + { | |
152 | + name: 'portable energy storage', | |
153 | + imageUrl: '/home/4-portableenergystorage.png', | |
154 | + href: '/pack' | |
155 | + } | |
156 | +] | |
157 | +</script> | ... | ... |
pages/pack.vue
0 → 100644
1 | +++ a/pages/pack.vue | |
1 | +<template> | |
2 | + <v-img src="/banner/pack.jpg" v-if="!isMobile()"></v-img> | |
3 | + <v-img src="/mobile/banner-pack.png" v-if="isMobile()"></v-img> | |
4 | + <div class="font-weight-bold tw-leading-[30px] text-white tw-bg-[url('/banner/top2.png')] tw-p-4 sm:tw-p-8"> | |
5 | + We are proud to introduce our PACK product to you. As a leader in the market application of | |
6 | + scientific research projects, we focus on transforming scientific achievements into practical | |
7 | + market applications. We provide a variety of cases to meet different project requirements, such | |
8 | + as fast-charging mobile power supplies, smart flashlights, low-speed vehicles, and small-scale | |
9 | + energy storage. We are committed to successfully applying the results of scientific research | |
10 | + projects to the market and providing innovative solutions for our customers." | |
11 | + </div> | |
12 | + <div class="tw-p-[32px] sm:tw-pt-[64px] sm:tw-px-[128px]"> | |
13 | + <div class="mb-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
14 | + <b>Pack Hardware</b> | |
15 | + </div> | |
16 | + <v-slide-group class="pa-4 tw-w-[110%] tw-ml-[-5%] tw-mb-[32px]" center-active show-arrows v-model="equipSlide" | |
17 | + v-if="!isMobile()"> | |
18 | + <v-slide-group-item v-for="n in hardwares" :key="n.title"> | |
19 | + <v-card :class="['ma-4']" width="300"> | |
20 | + <v-img :src="n.imageUrl" class="ma-2"></v-img> | |
21 | + <v-card-title class="tw-text-center text-subtitle-1">11{{ n.title }}</v-card-title> | |
22 | + </v-card> | |
23 | + </v-slide-group-item> | |
24 | + </v-slide-group> | |
25 | + <v-carousel height="310" width="318" interval="3000" cycle :continuous="false" :show-arrows="false" | |
26 | + hide-delimiter-background v-if="isMobile()"> | |
27 | + <v-carousel-item v-for="n in hardwares" :key="n.imageUrl"> | |
28 | + <v-sheet color="grey-lighten-1" height="310" width="318" class="mx-auto" border="none"> | |
29 | + <v-card-title class="tw-text-center text-subtitle-1">{{ n.title }}</v-card-title> | |
30 | + <v-img :src="n.imageUrl" alt="canrud"></v-img> | |
31 | + </v-sheet> | |
32 | + </v-carousel-item> | |
33 | + </v-carousel> | |
34 | + </div> | |
35 | + <div class="tw-p-[32px] sm:tw-py-[64px] sm:tw-px-[128px] bg-grey-lighten-5"> | |
36 | + <div class="mb-4 mb-sm-16 text-blue-darken-1 text-h5 text-sm-h4 tw-text-center"> | |
37 | + <b>Succeed Case</b> | |
38 | + </div> | |
39 | + <v-row class="mb-8"> | |
40 | + <v-col cols="12" sm="8"> | |
41 | + <v-img src="/pack_case/8.png"></v-img> | |
42 | + </v-col> | |
43 | + <v-col> | |
44 | + <div | |
45 | + class="text-subtitle-1 tw-text-justify tw-items-center tw-flex tw-h-full font-weight-medium text-grey-darken-1"> | |
46 | + Canrd helps our customer to accomplish the requirement from PET current collector to power | |
47 | + bank; | |
48 | + </div> | |
49 | + </v-col> | |
50 | + </v-row> | |
51 | + <v-divider class="my-8 my-sm-16"></v-divider> | |
52 | + <v-row class="mb-16"> | |
53 | + <v-col> | |
54 | + <div class="text-body-1 tw-h-full tw-text-justify font-weight-medium text-grey-darken-1"> | |
55 | + <p class="mb-3"> | |
56 | + 1. Canrd helps our customer to accomplish the requirement from sodium cathode to | |
57 | + standard car; | |
58 | + </p> | |
59 | + <p> | |
60 | + 2. Canrd is pleased to be the bridge between new material to cell and even to terminal | |
61 | + application product which can accelerate the R&D development; | |
62 | + </p> | |
63 | + </div> | |
64 | + </v-col> | |
65 | + <v-col cols="12" sm="8"> | |
66 | + <v-img src="/pack_case/9.png"></v-img> | |
67 | + </v-col> | |
68 | + </v-row> | |
69 | + </div> | |
70 | +</template> | |
71 | + | |
72 | +<script setup lang="ts"> | |
73 | +import { ref, onMounted, onUnmounted } from 'vue' | |
74 | +import { isMobile } from '~/utils' | |
75 | + | |
76 | +useHead({ | |
77 | + title: 'canrud', | |
78 | + meta: [{ | |
79 | + name: 'title', | |
80 | + content: | |
81 | + '科路得,PACK product,Market application,Scientific research projects,Practical market applications,Fast-charging mobile power supplies,Smart flashlights,Low-speed vehicles,Small-scale energy storage,Innovative solutions,Customer satisfaction', | |
82 | + }, { | |
83 | + name: 'keywords', | |
84 | + content: | |
85 | + '科路得,PACK product,Market application,Scientific research projects,Practical market applications,Fast-charging mobile power supplies,Smart flashlights,Low-speed vehicles,Small-scale energy storage,Innovative solutions,Customer satisfaction', | |
86 | + }, | |
87 | + { | |
88 | + name: 'description', | |
89 | + content: | |
90 | + '科路得,助您科研之路势在必得。We are proud to introduce our PACK product to you. As a leader in the market application of scientific research projects, we focus on transforming scientific achievements into practical market applications. We provide a variety of cases to meet different project requirements, such as fast-charging mobile power supplies, smart flashlights, low-speed vehicles, and small-scale energy storage. We are committed to successfully applying the results of scientific research projects to the market and providing innovative solutions for our customers."' | |
91 | + } | |
92 | + ] | |
93 | +}) | |
94 | + | |
95 | +const hardwares = [ | |
96 | + { title: '2000w laser-beam welding machine', imageUrl: '/pack_hardware/1.png' }, | |
97 | + { title: '5000A resistance welding machine', imageUrl: '/pack_hardware/2.png' }, | |
98 | + { title: 'Numerical control machine', imageUrl: '/pack_hardware/3.png' }, | |
99 | + { title: '5V 60A', imageUrl: '/pack_hardware/4.png' }, | |
100 | + { title: '5V3A', imageUrl: '/pack_hardware/5.png' }, | |
101 | + { title: '100V/120A', imageUrl: '/pack_hardware/6.png' }, | |
102 | + { title: 'Oscilloscope', imageUrl: '/pack_hardware/7.png' } | |
103 | +] | |
104 | + | |
105 | +const equipSlide = ref(1) | |
106 | +let equipTimer: any = null | |
107 | +onMounted(() => { | |
108 | + equipTimer = setInterval(() => { | |
109 | + if (equipSlide.value > hardwares.length) { | |
110 | + equipSlide.value = 0 | |
111 | + } else { | |
112 | + equipSlide.value = equipSlide.value + 1 | |
113 | + } | |
114 | + }, 2000) | |
115 | +}) | |
116 | + | |
117 | +onUnmounted(() => { | |
118 | + clearInterval(equipTimer) | |
119 | + equipTimer = null | |
120 | +}) | |
121 | +</script> | |
122 | + | |
123 | +<style lang="scss" scoped></style> | ... | ... |
pages/products/detail/[id]/index.vue
0 → 100644
1 | +++ a/pages/products/detail/[id]/index.vue | |
1 | +<template> | |
2 | + <MobileProductDetail v-if="isMobile()" :info="info" /> | |
3 | + <ProductDetail v-else :info="info" /> | |
4 | +</template> | |
5 | + | |
6 | +<script setup lang="ts"> | |
7 | +import {onMounted} from 'vue' | |
8 | +import ProductDetail from '~/components/ProductDetail.vue' | |
9 | +import MobileProductDetail from '~/components/MobileProductDetail.vue' | |
10 | +import type { Product, ProductImage } from '~/type' | |
11 | +import { useRoute } from 'vue-router' | |
12 | + | |
13 | +const route = useRoute() | |
14 | + | |
15 | +const info = ref<Partial<Product>>({ | |
16 | + productimageliststore: [], | |
17 | + productAttributeList: [], | |
18 | + name: '', | |
19 | + ticketTypes: [] | |
20 | +}) | |
21 | + | |
22 | +let { data: resData } = await useAsyncData('detail', () => $fetch('/shop/product/detail', { | |
23 | + method: 'POST', | |
24 | + headers: { | |
25 | + 'Content-Type': 'application/json' | |
26 | + }, | |
27 | + body: JSON.stringify({ id: route.params.id }) | |
28 | +}), { | |
29 | + server: true // 仅在服务器端获取数据 | |
30 | +}) | |
31 | + | |
32 | +const newData: Product = resData.value.data | |
33 | + | |
34 | +newData.productimageliststore = typeof newData.productimageliststore === 'string' ? | |
35 | + (JSON.parse(newData.productimageliststore) || []) : | |
36 | + newData.productimageliststore as ProductImage[] | |
37 | +newData.productimageliststore = newData?.productimageliststore.map((item: ProductImage) => ({ | |
38 | + ...item, | |
39 | + // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}` | |
40 | + url: `/api/show/image?fileKey=${item.fileKey}` | |
41 | +})) | |
42 | +info.value = { ...newData } | |
43 | + | |
44 | +</script> | ... | ... |
pages/products/index.vue
0 → 100644
1 | +++ a/pages/products/index.vue | |
1 | +<template> | |
2 | + <div class="tw-m-auto tw-pb-[64px]"> | |
3 | + <CategoryList v-if="categoryStore.categoryVisible && !isMobile()" /> | |
4 | + <MobileCategoryList v-if="categoryStore.categoryVisible && isMobile()" /> | |
5 | + <v-container class=""> | |
6 | + <div class="tw-text-center" v-if="loading"> | |
7 | + <v-progress-circular color="blue-lighten-2" indeterminate size="64" class="tw-m-auto"></v-progress-circular> | |
8 | + </div> | |
9 | + <v-item-group multiple> | |
10 | + <v-row v-if="!loading"> | |
11 | + <v-col v-for="(item, i) in productStore.list" :key="i" cols="6" lg="3" md="4" sm="6"> | |
12 | + <v-hover v-slot="{ isHovering, props }" open-delay="200"> | |
13 | + <v-card :elevation="isHovering ? 16 : 2" :class="{ 'on-hover': isHovering }" class="mx-auto" | |
14 | + v-bind="props" :to="`/products/detail/${item.id}`"> | |
15 | + <v-img :src="item.imgList[0].url" :alt="item.name"> | |
16 | + <!-- <v-expand-transition> | |
17 | + <div | |
18 | + v-if="isHovering" | |
19 | + class="d-flex transition-fast-in-fast-out bg-orange-darken-2 v-card--reveal tw-p-[12px] tw-text-justify" | |
20 | + style="height: 100%" | |
21 | + > | |
22 | + 产品描述描述描述描述描述描述描述描述 | |
23 | + </div> | |
24 | + </v-expand-transition> --> | |
25 | + </v-img> | |
26 | + <v-card-text class="tw-text-left font-weight-medium title">{{ | |
27 | + item.name | |
28 | + }}</v-card-text> | |
29 | + </v-card> | |
30 | + </v-hover> | |
31 | + </v-col> | |
32 | + </v-row> | |
33 | + <div v-if="!productStore.total && !loading" class="text-medium-emphasis text-body-1 tw-text-center tw-m-[64px]"> | |
34 | + no data | |
35 | + </div> | |
36 | + </v-item-group> | |
37 | + <v-row> | |
38 | + <v-col> | |
39 | + <v-pagination :size="isMobile() ? 'small' : 'default'" v-if="productStore.total" v-model="productStore.pageNo" | |
40 | + @update:modelValue="productStore.updatePageNo" :length="length" rounded="0" | |
41 | + class="tw-float-right tw-mt-[32px]" total-visible="5"></v-pagination></v-col></v-row> | |
42 | + </v-container> | |
43 | + </div> | |
44 | +</template> | |
45 | + | |
46 | +<script setup lang="ts"> | |
47 | +import { isMobile, isEqual } from '~/utils' | |
48 | +import { useProductListStore } from '~/stores/product_list' | |
49 | +import { useCategoryStore } from '~/stores/category' | |
50 | +import CategoryList from '~/components/CategoryList.vue' | |
51 | +import MobileCategoryList from '~/components/MobileCategoryList.vue' | |
52 | +import { watchEffect, computed, ref } from 'vue' | |
53 | + | |
54 | +const productStore = useProductListStore() | |
55 | +const categoryStore = useCategoryStore() | |
56 | +const loading = ref(false) | |
57 | + | |
58 | +useHead({ | |
59 | + title: 'canrud', | |
60 | + meta: [{ | |
61 | + name: 'title', | |
62 | + content: "科路得,助您科研之路势在必得。Canrd aims to be the world's leading one-stop service provider in new energy research. With a dedication to excellence, we offer Material Reagents, Lab Devices, Customized Batteries, Testing, and Advanced Packaging for energy materials and storage systems. We master advanced technologies to provide high-quality solutions. Our team's quick responses ensure tailored and professional services to meet your unique needs. Contact us at contact@canrd.com or call +86 19867737979 to explore our innovative offerings. Together, let's shape a greener, brighter world!" | |
63 | + }, { | |
64 | + name: 'keywords', | |
65 | + content: | |
66 | + '科路得,canrd,canrud,Energy Storage Research,Lithium Batteries Research,Material Reagents,Lab Device,Customized Battery,Testing,Pack', | |
67 | + }, | |
68 | + { | |
69 | + name: 'description', | |
70 | + content: | |
71 | + '科路得,助您科研之路势在必得。We offer a wide range of research materials and related equipment, technical services, and battery material performance evaluation in areas such as pouch cells, lithium-ion batteries, supercapacitors, lithium-sulfur batteries, fuel cells, lithium-air batteries, and sodium-ion batteries.' | |
72 | + } | |
73 | + ] | |
74 | +}) | |
75 | +watchEffect(async () => { | |
76 | + let params: any = { | |
77 | + pageNo: productStore.pageNo, | |
78 | + pageSize: 20 | |
79 | + } | |
80 | + | |
81 | + loading.value = true | |
82 | + if (productStore.keyword && !isEqual(productStore.params, params)) { | |
83 | + params.keyword = productStore.keyword | |
84 | + productStore.updateParams(params) | |
85 | + await productStore.getList(params) | |
86 | + loading.value = false | |
87 | + return | |
88 | + } | |
89 | + | |
90 | + params.productCategoryId = categoryStore.selectedSubCategory | |
91 | + // productCategoryId: '78b86c6e917841cf9a292234f2805e24', | |
92 | + | |
93 | + if (categoryStore.selectedFuncCategory) { | |
94 | + params.productFunctionId = categoryStore.selectedFuncCategory | |
95 | + } | |
96 | + | |
97 | + if (categoryStore.selectedSubCategory && !isEqual(productStore.params, params)) { | |
98 | + productStore.updateParams(params) | |
99 | + | |
100 | + await productStore.getList(params) | |
101 | + } | |
102 | + loading.value = false | |
103 | +}) | |
104 | + | |
105 | +const length = computed(() => | |
106 | + productStore.total ? Math.ceil(productStore.total / productStore.pageSize) : 0 | |
107 | +) | |
108 | +</script> | |
109 | + | |
110 | +<style scoped> | |
111 | +.title { | |
112 | + height: 60px; | |
113 | + overflow: hidden; | |
114 | + text-overflow: ellipsis; | |
115 | + display: -webkit-box; | |
116 | + -webkit-line-clamp: 2; | |
117 | + -webkit-box-orient: vertical; | |
118 | +} | |
119 | +</style> | ... | ... |
pages/test.vue
0 → 100644
1 | +++ a/pages/test.vue | |
1 | +<template> | |
2 | + <v-img src="/banner/test.jpg" v-if="!isMobile()"></v-img> | |
3 | + <v-img src="/mobile/banner-test.png" v-if="isMobile()"></v-img> | |
4 | + <div class="font-weight-bold tw-leading-[30px] text-white tw-bg-[url('/banner/top2.png')] px-4 py-2 pa-sm-8"> | |
5 | + We have an independent battery testing center that provides comprehensive testing services for | |
6 | + you! Whether it's ambient temperature, high-temperature cycling, rate testing, high and | |
7 | + low-temperature testing, high-temperature storage testing, or EIS/CV testing, we can meet your | |
8 | + needs. Our reverse analysis experimental plan covers various dimensions, including | |
9 | + non-destructive testing, disassembly analysis, size, capacity, internal resistance, EIS, rate, | |
10 | + high and low-temperature analysis. Through techniques such as capacity testing, SEM, EDS, | |
11 | + Mapping, CP, TG, GC-MS, ICP, we conduct in-depth reverse analysis, including elemental analysis | |
12 | + and morphology analysis. Finally, we prepare detailed reverse analysis reports, combining market | |
13 | + conditions to provide you with research and development directions. Choose us for reliable | |
14 | + testing and limitless innovation! | |
15 | + </div> | |
16 | + <div class="pa-8 pa-sm-16"> | |
17 | + <div class="mb-8 text-blue-darken-1 tw-text-center text-h5 text-sm-h4 mb-sm-6"> | |
18 | + <b>Test Hardware</b> | |
19 | + </div> | |
20 | + <v-slide-group selected-class="bg-primary" show-arrows v-model="equipSlide" v-if="!isMobile()"> | |
21 | + <v-slide-group-item v-for="(slide, index) in slides" :key="slide.title" :value="index"> | |
22 | + <v-card :class="['ma-4']" width="260"> | |
23 | + <v-img :src="slide.imageUrl"></v-img> | |
24 | + <v-card-title class="tw-text-center text-subtitle-1">{{ slide.title }}</v-card-title> | |
25 | + </v-card> | |
26 | + </v-slide-group-item> | |
27 | + </v-slide-group> | |
28 | + | |
29 | + <v-carousel height="360" width="318" interval="3000" cycle :continuous="false" :show-arrows="false" | |
30 | + hide-delimiter-background v-if="isMobile()"> | |
31 | + <v-carousel-item v-for="n in slides" :key="n.imageUrl"> | |
32 | + <v-sheet color="grey-lighten-1" height="360" width="318" class="mx-auto" border="none"> | |
33 | + <v-card-title class="tw-text-center text-subtitle-1">{{ n.title }}</v-card-title> | |
34 | + <v-img :src="n.imageUrl" alt="canrud"></v-img> | |
35 | + </v-sheet> | |
36 | + </v-carousel-item> | |
37 | + </v-carousel> | |
38 | + </div> | |
39 | + <!-- <v-slide-group class="pa-4" selected-class="bg-success" show-arrows> | |
40 | + <v-slide-group-item v-for="slide in slides" :key="slide"> | |
41 | + <v-card :class="['ma-2']" width="360"> | |
42 | + <v-img :src="slide"></v-img> | |
43 | + </v-card> | |
44 | + </v-slide-group-item> | |
45 | + </v-slide-group> --> | |
46 | + <div class="tw-p-[64px] bg-grey-lighten-5"> | |
47 | + <div class="mb-4 mb-sm-16 text-blue-darken-1 text-h5 text-sm-h4 tw-text-center"> | |
48 | + <b>Succeed Case</b> | |
49 | + </div> | |
50 | + <div class="mb-8 mb-sm-16 tw-relative"> | |
51 | + <div | |
52 | + class="tw-w-[200px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-text-[20px] tw-font-medium tw-relative"> | |
53 | + Reverse analysis | |
54 | + </div> | |
55 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
56 | + </div> | |
57 | + <ContentDescription className="mb-0 mb-sm-16 tw-max-w-[600px] tw-m-auto text-grey-darken-1" | |
58 | + content="Reverse analysis: assist customers to analyze the polymer / organic components in mainstream power batteries" /> | |
59 | + <v-row class="mb-8 mb-sm-12"> | |
60 | + <v-col cols="0" sm="2"></v-col> | |
61 | + <v-col v-for="slide in testCases" :key="slide" cols="6" sm="4"> | |
62 | + <v-img :src="slide"></v-img> | |
63 | + </v-col> | |
64 | + </v-row> | |
65 | + <div class="font-weight-medium tw-max-w-[600px] tw-m-auto text-grey-darken-1"> | |
66 | + <p> | |
67 | + 1. Experiment scheme: first conduct nondestructive testing (size / capacity / internal | |
68 | + resistance / EIS / ratio / high and low temperature, etc.), and finally conduct disassembly | |
69 | + analysis | |
70 | + </p> | |
71 | + <p> | |
72 | + 2. Implement reverse analysis: gram capacity / SEM / ED S/Mapping / CP / TG / GC-MS / ICP | |
73 | + and other means | |
74 | + </p> | |
75 | + <p> | |
76 | + 3. Write the reverse analysis report: give the customer research and development direction | |
77 | + according to the market situation | |
78 | + </p> | |
79 | + </div> | |
80 | + | |
81 | + <div class="my-8 my-sm-16 tw-relative"> | |
82 | + <div | |
83 | + class="tw-w-[240px] tw-text-center bg-blue-darken-1 tw-rounded-[4px] tw-m-auto tw-text-[20px] tw-font-medium tw-relative"> | |
84 | + Reverse analysis result | |
85 | + </div> | |
86 | + <v-divider class="tw-absolute tw-top-[16px] tw-w-full"></v-divider> | |
87 | + </div> | |
88 | + | |
89 | + <v-img :height="isMobile() ? 100 : 300" :src="results[0]" class="mb-8 mb-sm-16"></v-img> | |
90 | + <v-img :height="isMobile() ? 100 : 340" class="tw-mb-[32px]" :src="results[1]"></v-img> | |
91 | + </div> | |
92 | + <!-- <v-slide-group class="pa-0" selected-class="bg-success" show-arrows> | |
93 | + <v-slide-group-item v-for="slide in slideCases" :key="slide"> | |
94 | + <v-card :class="['ma-2']" width="360"> | |
95 | + <v-img :src="slide"></v-img> | |
96 | + </v-card> | |
97 | + </v-slide-group-item> | |
98 | + </v-slide-group> --> | |
99 | +</template> | |
100 | + | |
101 | +<script setup lang="ts"> | |
102 | +import ContentDescription from '@/components/ContentDescription.vue' | |
103 | +import { onMounted, onUnmounted, ref } from 'vue' | |
104 | +import { isMobile } from '~/utils' | |
105 | + | |
106 | +useHead({ | |
107 | + title: 'canrud', | |
108 | + meta: [{ | |
109 | + name: 'title', | |
110 | + content: | |
111 | + '科路得,Battery testing center,Comprehensive testing services,Ambient temperature,High-temperature cycling,Rate testing,High and low-temperature testing,High-temperature storage testing,EIS/CV testing,Reverse analysis experimental plan,Elemental analysis', | |
112 | + }, { | |
113 | + name: 'keywords', | |
114 | + content: | |
115 | + '科路得,Battery testing center,Comprehensive testing services,Ambient temperature,High-temperature cycling,Rate testing,High and low-temperature testing,High-temperature storage testing,EIS/CV testing,Reverse analysis experimental plan,Elemental analysis', | |
116 | + }, | |
117 | + { | |
118 | + name: 'description', | |
119 | + content: | |
120 | + '科路得,助您科研之路势在必得。We have an independent battery testing center that provides comprehensive testing services for you! Whether it‘s ambient temperature, high-temperature cycling, rate testing, high and low-temperature testing, high-temperature storage testing, or EIS/CV testing, we can meet your needs. Our reverse analysis experimental plan covers various dimensions, including non-destructive testing, disassembly analysis, size, capacity, internal resistance, EIS, rate, high and low-temperature analysis. Through techniques such as capacity testing, SEM, EDS, Mapping, CP, TG, GC-MS, ICP, we conduct in-depth reverse analysis, including elemental analysis and morphology analysis. Finally, we prepare detailed reverse analysis reports, combining market conditions to provide you with research and development directions. Choose us for reliable testing and limitless innovation!' | |
121 | + } | |
122 | + ] | |
123 | +}) | |
124 | + | |
125 | +const slides = [ | |
126 | + { title: 'Cycle/Rate test', imageUrl: '/testing_hardware/1.png' }, | |
127 | + { title: 'H/L temperature oven', imageUrl: '/testing_hardware/2.png' }, | |
128 | + { title: 'High temperature oven', imageUrl: '/testing_hardware/3.png' }, | |
129 | + { title: 'Electrochemical workstation', imageUrl: '/testing_hardware/4.png' }, | |
130 | + { title: 'BET', imageUrl: '/testing_hardware/5.png' }, | |
131 | + { title: 'TG-DSC', imageUrl: '/testing_hardware/6.png' }, | |
132 | + { title: 'Raman', imageUrl: '/testing_hardware/7.png' }, | |
133 | + { title: 'XRD', imageUrl: '/testing_hardware/8.png' } | |
134 | +] | |
135 | + | |
136 | +const testCases = ['/test_result/3.png', '/test_result/4.png'] | |
137 | + | |
138 | +const results = ['/test_result/1.png', '/test_result/2.png'] | |
139 | + | |
140 | +const equipSlide = ref(1) | |
141 | +let equipTimer: any = null | |
142 | +onMounted(() => { | |
143 | + equipTimer = setInterval(() => { | |
144 | + if (equipSlide.value >= slides.length) { | |
145 | + equipSlide.value = 0 | |
146 | + } else { | |
147 | + equipSlide.value = equipSlide.value + 1 | |
148 | + } | |
149 | + }, 2000) | |
150 | +}) | |
151 | + | |
152 | +onUnmounted(() => { | |
153 | + clearInterval(equipTimer) | |
154 | + equipTimer = null | |
155 | +}) | |
156 | +</script> | |
157 | + | |
158 | +<style lang="less" scoped></style> | ... | ... |