import codes
25
src/App.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
16
src/assets/icons/angle-double-left.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M9.828 8.064l4.243 4.243a1 1 0 1 1-1.414 1.414l-4.95-4.95a1 1 0 0 1 0-1.414l4.95-4.95a1 1 0 0 1 1.414 1.414L9.828 8.064zm-6 0l4.243 4.243a1 1 0 1 1-1.414 1.414l-4.95-4.95a1 1 0 0 1 0-1.414l4.95-4.95A1 1 0 0 1 8.07 3.821L3.828 8.064z" fill="#000" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
16
src/assets/icons/angle-double-right.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M5.95 8.064L1.707 3.821a1 1 0 0 1 1.414-1.414l4.95 4.95a1 1 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.414L5.95 8.064zm6 0L7.707 3.821a1 1 0 0 1 1.414-1.414l4.95 4.95a1 1 0 0 1 0 1.414l-4.95 4.95a1 1 0 0 1-1.414-1.414l4.243-4.243z" fill="#000" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
16
src/assets/icons/arrow-down.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path id="a" d="m10.472352 7.28232367c.3431062-.36783247.904419-.36783247 1.2592596-.00644059.3578153.36442148.3578153.95850784.0002156 1.28561559l-3.10532264 3.16826253c-.17025689.1734002-.39845625.2702388-.62654793.2702388-.24380864 0-.45151514-.0919745-.62697852-.2706782l-3.09835734-3.16693764c-.36405333-.352236-.36405333-.94614513-.01248284-1.28566765.34310619-.36783247.90441901-.36783247 1.25901327-.0066912l2.48658215 2.52737493z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
20
src/assets/icons/assignment.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>assignment</title>
|
||||
<path d="M17.016 9v-2.016h-10.031v2.016h10.031zM17.016 12.984v-1.969h-10.031v1.969h10.031zM14.016 17.016v-2.016h-7.031v2.016h7.031zM12 3q-0.422 0-0.703 0.281t-0.281 0.703 0.281 0.727 0.703 0.305 0.703-0.305 0.281-0.727-0.281-0.703-0.703-0.281zM18.984 3q0.797 0 1.406 0.609t0.609 1.406v13.969q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-13.969q0-0.797 0.609-1.406t1.406-0.609h4.172q0.328-0.891 1.078-1.453t1.734-0.563 1.734 0.563 1.078 1.453h4.172z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
19
src/assets/icons/av_timer.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>av_timer</title>
|
||||
<path d="M6 12q0-0.422 0.281-0.703t0.703-0.281 0.727 0.281 0.305 0.703-0.305 0.703-0.727 0.281-0.703-0.281-0.281-0.703zM18 12q0 0.422-0.281 0.703t-0.703 0.281-0.727-0.281-0.305-0.703 0.305-0.703 0.727-0.281 0.703 0.281 0.281 0.703zM11.016 3h0.984q3.75 0 6.375 2.625t2.625 6.375-2.625 6.375-6.375 2.625-6.375-2.625-2.625-6.375q0-4.5 3.609-7.172v-0.047l6.797 6.797-1.406 1.406-5.438-5.391q-1.547 1.922-1.547 4.406 0 2.906 2.039 4.945t4.945 2.039 4.945-2.039 2.039-4.945q0-2.625-1.734-4.594t-4.266-2.344v1.922h-1.969v-3.984zM11.016 17.016q0-0.422 0.281-0.727t0.703-0.305 0.703 0.305 0.281 0.727-0.281 0.703-0.703 0.281-0.703-0.281-0.281-0.703z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
19
src/assets/icons/bar_chart.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>bar_chart</title>
|
||||
<path d="M16.219 12.984h2.766v6h-2.766v-6zM10.594 5.016h2.813v13.969h-2.813v-13.969zM5.016 9.188h3v9.797h-3v-9.797z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1021 B |
16
src/assets/icons/chart.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/chart</title><path d="M5.55 3.824L6.853 5.78a.3.3 0 0 0 .384.102l1.526-.764a.3.3 0 0 1 .384.102l1.65 2.476a.3.3 0 0 0 .462.045l1.229-1.229a.3.3 0 0 1 .512.212v4.243H5V3.99a.3.3 0 0 1 .55-.167zM13 12a1 1 0 0 1 0 2H3.833A1.833 1.833 0 0 1 2 12.167V3a1 1 0 1 1 2 0v9h9z" id="a"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
16
src/assets/icons/chevron-left.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/chevron-left</title><path d="M7.414 7.989l2.295 2.306a1 1 0 1 1-1.418 1.41l-3-3.015a1 1 0 0 1 .004-1.414l3-2.985a1 1 0 1 1 1.41 1.418l-2.29 2.28z" id="a"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
16
src/assets/icons/chevron-right.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/chevron-right</title><path d="M8.586 7.989l-2.291-2.28a1 1 0 1 1 1.41-1.418l3 2.985a1 1 0 0 1 .004 1.414l-3 3.015a1 1 0 0 1-1.418-1.41l2.295-2.306z" id="a"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
19
src/assets/icons/dashboard_customize.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>dashboard_customize</title>
|
||||
<path d="M18 12.984v3h3v2.016h-3v3h-2.016v-3h-3v-2.016h3v-3h2.016zM3 12.984h8.016v8.016h-8.016v-8.016zM12.984 3h8.016v8.016h-8.016v-8.016zM3 3h8.016v8.016h-8.016v-8.016z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
16
src/assets/icons/epic.svg
Executable file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>icn/epic</title><path d="M5.156 4l-.811 2h7.31l-.811-2H5.156zM4.55 2h6.9c.368 0 .702.235.85.6l1.622 4c.205.505-.009 1.095-.478 1.316a.87.87 0 0 1-.371.084H2.927C2.415 8 2 7.552 2 7c0-.138.026-.274.078-.4l1.622-4c.148-.365.481-.6.85-.6zM3 9h10a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2zm0 3h10a1 1 0 0 1 0 2H3a1 1 0 0 1 0-2z" id="a"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
18
src/assets/icons/format_indent_decrease.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>format_indent_decrease</title>
|
||||
<path d="M11.016 12.984v-1.969h9.984v1.969h-9.984zM11.016 9v-2.016h9.984v2.016h-9.984zM3 3h18v2.016h-18v-2.016zM3 21v-2.016h18v2.016h-18zM3 12l3.984-3.984v7.969zM11.016 17.016v-2.016h9.984v2.016h-9.984z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
15
src/assets/icons/health.svg
Normal file
@@ -0,0 +1,15 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="16px" height="16.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="M432 617.6l-121.6-121.6L265.6 544l166.4 166.4L758.4 384l-44.8-48z" /></svg>
|
20
src/assets/icons/index.ts
Executable file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const requireAll = (requireContext: Recordable) =>
|
||||
requireContext.keys().map(requireContext);
|
||||
const req = require.context("./", true, /\.svg$/);
|
||||
requireAll(req);
|
32
src/assets/icons/logo-sw.svg
Normal file
29
src/assets/icons/logo.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="3450px" height="1823px" viewBox="0 0 3450 1823" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 51.3 (57544) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group" transform="translate(0.000000, -29.000000)">
|
||||
<path d="M1050.01772,1394.31899 C1050.01772,1615.24051 912.21519,1851.47342 474.746835,1851.47342 C310.696203,1851.47342 192.579747,1836.16203 87.5873418,1812.10127 C65.7139241,1807.72658 46.0278481,1792.41519 46.0278481,1768.35443 L46.0278481,1610.86582 C46.0278481,1586.80506 65.7139241,1569.30633 87.5873418,1569.30633 L91.9620253,1569.30633 C179.455696,1580.24304 398.189873,1591.17975 479.121519,1591.17975 C673.794937,1591.17975 732.853165,1521.18481 732.853165,1394.31899 C732.853165,1309.01266 691.293671,1265.26582 546.929114,1179.95949 L258.2,1007.15949 C54.7772152,886.855696 0.0936708861,759.989873 0.0936708861,606.875949 C0.0936708861,366.268354 140.083544,191.281013 546.929114,191.281013 C691.293671,191.281013 892.529114,213.15443 966.898734,230.653165 C988.772152,235.027848 1006.27089,250.339241 1006.27089,272.212658 L1006.27089,434.075949 C1006.27089,455.949367 990.959494,473.448101 969.086076,473.448101 L964.711392,473.448101 C820.346835,460.324051 675.982278,451.574684 533.805063,451.574684 C371.941772,451.574684 304.134177,508.44557 304.134177,606.875949 C304.134177,679.058228 341.318987,722.805063 483.496203,801.549367 L745.977215,948.101266 C986.58481,1081.52911 1050.01772,1221.51899 1050.01772,1394.31899 Z M2852.63038,644.060759 C2852.63038,646.248101 2852.63038,648.435443 2852.63038,650.622785 L2653.58228,1656.8 C2627.33418,1788.04051 2592.33671,1840.53671 2458.90886,1840.53671 L2399.85063,1840.53671 C2281.73418,1840.53671 2220.48861,1783.66582 2192.05316,1669.92405 L2019.25316,1000.59747 C2017.06582,991.848101 2017.06582,989.660759 2012.69114,989.660759 C2008.31646,989.660759 2008.31646,991.848101 2006.12911,1000.59747 L1833.32911,1669.92405 C1804.89367,1783.66582 1743.6481,1840.53671 1625.53165,1840.53671 L1566.47342,1840.53671 C1433.04557,1840.53671 1398.0481,1788.04051 1371.8,1656.8 L1172.7519,650.622785 C1172.7519,648.435443 1172.7519,646.248101 1172.7519,644.060759 C1172.7519,620 1192.43797,600.313924 1216.49873,600.313924 L1428.67089,600.313924 C1450.5443,600.313924 1465.8557,620 1468.04304,639.686076 L1605.84557,1564.93165 C1608.03291,1584.61772 1612.40759,1595.55443 1616.78228,1595.55443 C1621.15696,1595.55443 1627.71899,1586.80506 1632.09367,1564.93165 L1813.64304,829.98481 C1835.51646,744.678481 1861.76456,735.929114 1936.13418,735.929114 L2089.2481,735.929114 C2163.61772,735.929114 2189.86582,744.678481 2211.73924,829.98481 L2393.28861,1564.93165 C2397.66329,1586.80506 2404.22532,1595.55443 2408.6,1595.55443 C2412.97468,1595.55443 2417.34937,1584.61772 2419.53671,1564.93165 L2557.33924,639.686076 C2559.52658,620 2574.83797,600.313924 2596.71139,600.313924 L2808.88354,600.313924 C2832.9443,600.313924 2852.63038,620 2852.63038,644.060759 Z" id="Sw" fill="#1368B3"></path>
|
||||
<g id="moon-o" transform="translate(2932.164557, 596.000000) rotate(-183.000000) translate(-2932.164557, -596.000000) translate(2415.708861, 26.379747)" fill="#D8D8D8" fill-rule="nonzero">
|
||||
<path d="M1025.31646,927.371333 C992.796119,932.841177 959.292071,935.576099 925.845888,935.576099 C590.40035,935.576099 318.259524,661.909325 318.259524,324.582876 C318.259524,209.134252 351.705707,96.3623597 412.290747,0 C171.802278,71.8062511 0,293.684076 0,557.342199 C0,878.317305 259.46831,1139.24051 578.65368,1139.24051 C753.17563,1139.24051 916.818891,1059.22949 1025.31646,927.371333 Z" id="Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
18
src/assets/icons/notification_important.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>notification_important</title>
|
||||
<path d="M12 21.984q-0.844 0-1.43-0.563t-0.586-1.406h4.031q0 0.797-0.609 1.383t-1.406 0.586zM12.984 12v-3.984h-1.969v3.984h1.969zM12.984 15.984v-1.969h-1.969v1.969h1.969zM18 15.984l2.016 2.016v0.984h-16.031v-0.984l2.016-2.016v-4.969q0-2.344 1.195-4.078t3.305-2.25v-0.703q0-0.609 0.422-1.055t1.078-0.445 1.078 0.445 0.422 1.055v0.703q2.109 0.516 3.305 2.25t1.195 4.078v4.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
18
src/assets/icons/playlist_add.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>playlist_add</title>
|
||||
<path d="M2.016 15.984v-1.969h7.969v1.969h-7.969zM18 14.016h3.984v1.969h-3.984v4.031h-2.016v-4.031h-3.984v-1.969h3.984v-4.031h2.016v4.031zM14.016 6v2.016h-12v-2.016h12zM14.016 9.984v2.016h-12v-2.016h12z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
18
src/assets/icons/scatter_plot.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>scatter_plot</title>
|
||||
<path d="M13.594 17.578q0-1.219 0.891-2.109t2.109-0.891 2.109 0.891 0.891 2.109-0.891 2.109-2.109 0.891-2.109-0.891-0.891-2.109zM8.016 6q0-1.219 0.891-2.109t2.109-0.891 2.109 0.891 0.891 2.109-0.891 2.109-2.109 0.891-2.109-0.891-0.891-2.109zM3.984 14.016q0-1.219 0.891-2.109t2.109-0.891 2.109 0.891 0.891 2.109-0.891 2.109-2.109 0.891-2.109-0.891-0.891-2.109z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
18
src/assets/icons/settings.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>settings</title>
|
||||
<path d="M12 15.516q1.453 0 2.484-1.031t1.031-2.484-1.031-2.484-2.484-1.031-2.484 1.031-1.031 2.484 1.031 2.484 2.484 1.031zM19.453 12.984l2.109 1.641q0.328 0.234 0.094 0.656l-2.016 3.469q-0.188 0.328-0.609 0.188l-2.484-0.984q-0.984 0.703-1.688 0.984l-0.375 2.625q-0.094 0.422-0.469 0.422h-4.031q-0.375 0-0.469-0.422l-0.375-2.625q-0.891-0.375-1.688-0.984l-2.484 0.984q-0.422 0.141-0.609-0.188l-2.016-3.469q-0.234-0.422 0.094-0.656l2.109-1.641q-0.047-0.328-0.047-0.984t0.047-0.984l-2.109-1.641q-0.328-0.234-0.094-0.656l2.016-3.469q0.188-0.328 0.609-0.188l2.484 0.984q0.984-0.703 1.688-0.984l0.375-2.625q0.094-0.422 0.469-0.422h4.031q0.375 0 0.469 0.422l0.375 2.625q0.891 0.375 1.688 0.984l2.484-0.984q0.422-0.141 0.609 0.188l2.016 3.469q0.234 0.422-0.094 0.656l-2.109 1.641q0.047 0.328 0.047 0.984t-0.047 0.984z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
18
src/assets/icons/timeline.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>timeline</title>
|
||||
<path d="M23.016 8.016q0 0.797-0.609 1.383t-1.406 0.586h-0.047q-0.328 0-0.469-0.047l-3.563 3.563q0.094 0.281 0.094 0.516 0 0.797-0.609 1.383t-1.406 0.586-1.406-0.586-0.609-1.383q0-0.234 0.094-0.516l-2.578-2.578q-0.281 0.094-0.516 0.094t-0.516-0.094l-4.547 4.547q0.094 0.281 0.094 0.516 0 0.797-0.609 1.406t-1.406 0.609-1.406-0.609-0.609-1.406 0.609-1.383 1.406-0.586q0.375 0 0.516 0.047l4.547-4.547q-0.047-0.141-0.047-0.516 0-0.797 0.586-1.406t1.383-0.609 1.406 0.609 0.609 1.406q0 0.375-0.047 0.516l2.531 2.531q0.141-0.047 0.516-0.047t0.516 0.047l3.563-3.516q-0.094-0.281-0.094-0.516 0-0.797 0.609-1.406t1.406-0.609 1.406 0.609 0.609 1.406z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
765
src/components/DateCalendar.vue
Executable file
@@ -0,0 +1,765 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div :class="`${state.pre}`">
|
||||
<div :class="`${state.pre}-head`">
|
||||
<a
|
||||
:class="`${state.pre}-prev-decade-btn`"
|
||||
v-show="state.showYears"
|
||||
@click="state.year -= 10"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-left" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-prev-year-btn`"
|
||||
v-show="!state.showYears"
|
||||
@click="state.year--"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-left" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-prev-month-btn`"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
@click="pm"
|
||||
>
|
||||
<Icon size="middle" iconName="chevron-left" />
|
||||
</a>
|
||||
<a :class="`${state.pre}-year-select`" v-show="state.showYears">{{
|
||||
ys + "-" + ye
|
||||
}}</a>
|
||||
<template v-if="local.yearSuffix">
|
||||
<a
|
||||
:class="`${state.pre}-year-select`"
|
||||
@click="state.showYears = !state.showYears"
|
||||
v-show="!state.showYears"
|
||||
>{{ state.year }}{{ local.yearSuffix }}</a
|
||||
>
|
||||
<a
|
||||
:class="`${state.pre}-month-select`"
|
||||
@click="state.showMonths = !state.showMonths"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
>{{ local.monthsHead[state.month] }}</a
|
||||
>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a
|
||||
:class="`${state.pre}-month-select`"
|
||||
@click="state.showMonths = !state.showMonths"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
>{{ local.monthsHead[state.month] }}</a
|
||||
>
|
||||
<a
|
||||
:class="`${state.pre}-year-select`"
|
||||
@click="state.showYears = !state.showYears"
|
||||
v-show="!state.showYears"
|
||||
>{{ state.year }}</a
|
||||
>
|
||||
</template>
|
||||
<a
|
||||
:class="`${state.pre}-next-month-btn`"
|
||||
v-show="!state.showYears && !state.showMonths"
|
||||
@click="nm"
|
||||
>
|
||||
<Icon size="middle" iconName="chevron-right" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-next-year-btn`"
|
||||
v-show="!state.showYears"
|
||||
@click="state.year++"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-right" />
|
||||
</a>
|
||||
<a
|
||||
:class="`${state.pre}-next-decade-btn`"
|
||||
v-show="state.showYears"
|
||||
@click="state.year += 10"
|
||||
>
|
||||
<Icon size="sm" iconName="angle-double-right" />
|
||||
</a>
|
||||
</div>
|
||||
<div :class="`${state.pre}-body`">
|
||||
<div :class="`${state.pre}-days`">
|
||||
<a :class="`${state.pre}-week`" v-for="i in local.weeks" :key="i">{{
|
||||
i
|
||||
}}</a>
|
||||
<a
|
||||
v-for="(j, i) in days"
|
||||
@click="is($event) && ((state.day = j.i), ok(j))"
|
||||
:class="[
|
||||
j.p || j.n ? `${state.pre}-date-out` : '',
|
||||
status(
|
||||
j.y,
|
||||
j.m,
|
||||
j.i,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMMDD'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ j.i }}</a
|
||||
>
|
||||
</div>
|
||||
<div :class="`${state.pre}-months`" v-show="state.showMonths">
|
||||
<a
|
||||
v-for="(i, j) in local.months"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showMonths = m === 'M'),
|
||||
(state.month = j),
|
||||
m === 'M' && ok('m'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
j,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMM'
|
||||
),
|
||||
]"
|
||||
:key="j"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
<div :class="`${state.pre}-years`" v-show="state.showYears">
|
||||
<a
|
||||
v-for="(i, j) in years"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showYears = m === 'Y'),
|
||||
(state.year = i),
|
||||
state.m === 'Y' && ok('y'))
|
||||
"
|
||||
:class="[
|
||||
j === 0 || j === 11 ? `${state.pre}-date-out` : '',
|
||||
status(
|
||||
i,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYY'
|
||||
),
|
||||
]"
|
||||
:key="j"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
<div :class="`${state.pre}-hours scroll_hide`" v-show="state.showHours">
|
||||
<div :class="`${state.pre}-title`">{{ local.hourTip }}</div>
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 24"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showHours = false), (state.hour = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
i,
|
||||
state.minute,
|
||||
state.second,
|
||||
'YYYYMMDDHH'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${state.pre}-minutes`" v-show="state.showMinutes">
|
||||
<div :class="`${state.pre}-title`">{{ local.minuteTip }}</div>
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 60"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showMinutes = false), (state.minute = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
i,
|
||||
state.second,
|
||||
'YYYYMMDDHHmm'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${state.pre}-seconds`" v-show="state.showSeconds">
|
||||
<div :class="`${state.pre}-title`">{{ local.secondTip }}</div>
|
||||
<div class="scroll_hide calendar-overflow">
|
||||
<a
|
||||
v-for="(j, i) in 60"
|
||||
@click="
|
||||
is($event) &&
|
||||
((state.showSeconds = false), (state.second = i), ok('h'))
|
||||
"
|
||||
:class="[
|
||||
status(
|
||||
state.year,
|
||||
state.month,
|
||||
state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
i,
|
||||
'YYYYMMDDHHmmss'
|
||||
),
|
||||
]"
|
||||
:key="i"
|
||||
>{{ i }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${state.pre}-foot`">
|
||||
<div :class="`${state.pre}-hour`">
|
||||
<a
|
||||
:title="local.hourTip"
|
||||
@click="
|
||||
(state.showHours = !state.showHours),
|
||||
(state.showMinutes = state.showSeconds = false)
|
||||
"
|
||||
:class="{ on: state.showHours }"
|
||||
>{{ state.hour || dd }}</a
|
||||
>
|
||||
<span>:</span>
|
||||
<a
|
||||
:title="local.minuteTip"
|
||||
@click="
|
||||
(state.showMinutes = !state.showMinutes),
|
||||
(state.showHours = state.showSeconds = false)
|
||||
"
|
||||
:class="{ on: state.showMinutes }"
|
||||
>{{ state.minute || dd }}</a
|
||||
>
|
||||
<span v-show="state.m !== 'D'">
|
||||
<span>:</span>
|
||||
<a
|
||||
:title="local.secondTip"
|
||||
@click="
|
||||
(state.showSeconds = !state.showSeconds),
|
||||
(state.showHours = state.showMinutes = false)
|
||||
"
|
||||
:class="{ on: state.showSeconds }"
|
||||
>{{ state.second || dd }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineProps,
|
||||
computed,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
watch,
|
||||
reactive,
|
||||
} from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
value: { type: Date },
|
||||
left: { type: Boolean, default: false },
|
||||
right: { type: Boolean, default: false },
|
||||
dates: { default: [] },
|
||||
disabledDate: { type: Function, default: () => false },
|
||||
format: {
|
||||
type: String,
|
||||
default: "YYYY-MM-DD",
|
||||
},
|
||||
});
|
||||
const state = reactive({
|
||||
pre: "",
|
||||
m: "",
|
||||
showYears: false,
|
||||
showMonths: false,
|
||||
showHours: false,
|
||||
showMinutes: false,
|
||||
showSeconds: false,
|
||||
year: 0,
|
||||
month: 0,
|
||||
day: 0,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
});
|
||||
const get = (time: Date): { [key: string]: any } => {
|
||||
return {
|
||||
year: time.getFullYear(),
|
||||
month: time.getMonth(),
|
||||
day: time.getDate(),
|
||||
hour: time.getHours(),
|
||||
minute: time.getMinutes(),
|
||||
second: time.getSeconds(),
|
||||
};
|
||||
};
|
||||
if (props.value) {
|
||||
const time = get(props.value);
|
||||
state.pre = "calendar";
|
||||
state.m = "D";
|
||||
state.showYears = false;
|
||||
state.showMonths = false;
|
||||
state.showHours = false;
|
||||
state.showMinutes = false;
|
||||
state.showSeconds = false;
|
||||
state.year = time.year;
|
||||
state.month = time.month;
|
||||
state.day = time.day;
|
||||
state.hour = time.hour;
|
||||
state.minute = time.minute;
|
||||
state.second = time.second;
|
||||
}
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: Date | undefined) => {
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
const time = get(val);
|
||||
state.year = time.year;
|
||||
state.month = time.month;
|
||||
state.day = time.day;
|
||||
state.hour = time.hour;
|
||||
state.minute = time.minute;
|
||||
state.second = time.second;
|
||||
}
|
||||
);
|
||||
const parse = (num: number): number => {
|
||||
return Math.floor(num / 1000);
|
||||
};
|
||||
const start = computed(() => {
|
||||
return parse(props.dates[0]);
|
||||
});
|
||||
const end = computed(() => {
|
||||
return parse(props.dates[1]);
|
||||
});
|
||||
const ys = computed(() => {
|
||||
return Math.floor(state.year / 10) * 10;
|
||||
});
|
||||
const ye = computed(() => {
|
||||
return ys.value + 10;
|
||||
});
|
||||
const years = computed(() => {
|
||||
const arr = [];
|
||||
let start = ys.value - 1;
|
||||
while (arr.length < 12) {
|
||||
arr.push((start += 1));
|
||||
}
|
||||
return arr;
|
||||
});
|
||||
const local = computed(() => {
|
||||
return {
|
||||
dow: 1, // Monday is the first day of the week
|
||||
hourTip: t("hourTip"), // tip of select hour
|
||||
minuteTip: t("minuteTip"), // tip of select minute
|
||||
secondTip: t("secondTip"), // tip of select second
|
||||
yearSuffix: t("yearSuffix"), // format of head
|
||||
monthsHead: t("monthsHead").split("_"), // months of head
|
||||
months: t("months").split("_"), // months of panel
|
||||
weeks: t("weeks").split("_"), // weeks
|
||||
cancelTip: t("cancel"), // default text for cancel button
|
||||
submitTip: t("confirm"), // default text for submit button
|
||||
quarterHourCutTip: t("quarterHourCutTip"),
|
||||
halfHourCutTip: t("halfHourCutTip"),
|
||||
hourCutTip: t("hourCutTip"),
|
||||
dayCutTip: t("dayCutTip"),
|
||||
weekCutTip: t("weekCutTip"),
|
||||
monthCutTip: t("monthCutTip"),
|
||||
};
|
||||
});
|
||||
const days = computed(() => {
|
||||
const days = [];
|
||||
const year = state.year;
|
||||
const month = state.month;
|
||||
const time = new Date(year, month, 1);
|
||||
const dow = local.value.dow || 7;
|
||||
time.setDate(0); // switch to the last day of last month
|
||||
let lastDay = time.getDate();
|
||||
const week = time.getDay() || 7;
|
||||
let count = dow <= week ? week - dow + 1 : week + (7 - dow + 1);
|
||||
while (count > 0) {
|
||||
days.push({
|
||||
i: lastDay - count + 1,
|
||||
y: month > 0 ? year : year - 1,
|
||||
m: month > 0 ? month - 1 : 11,
|
||||
p: true,
|
||||
});
|
||||
count--;
|
||||
}
|
||||
time.setMonth(time.getMonth() + 2, 0); // switch to the last day of the current month
|
||||
lastDay = time.getDate();
|
||||
let i = 1;
|
||||
for (i = 1; i <= lastDay; i++) {
|
||||
days.push({
|
||||
i: i,
|
||||
y: year,
|
||||
m: month,
|
||||
});
|
||||
}
|
||||
for (i = 1; days.length < 42; i++) {
|
||||
days.push({
|
||||
i: i,
|
||||
y: month < 11 ? year : year + 1,
|
||||
m: month < 11 ? month + 1 : 0,
|
||||
n: true,
|
||||
});
|
||||
}
|
||||
return days;
|
||||
});
|
||||
const dd = (val: number) => ("0" + val).slice(-2);
|
||||
const status = (
|
||||
year: number,
|
||||
month: number,
|
||||
day: number,
|
||||
hour: number,
|
||||
minute: number,
|
||||
second: number,
|
||||
format: string
|
||||
) => {
|
||||
const maxDay = new Date(year, month + 1, 0).getDate();
|
||||
const time: any = new Date(
|
||||
year,
|
||||
month,
|
||||
day > maxDay ? maxDay : day,
|
||||
hour,
|
||||
minute,
|
||||
second
|
||||
);
|
||||
const t = parse(time);
|
||||
const tf = (time?: Date, format?: any): string => {
|
||||
if (!time) {
|
||||
return "";
|
||||
}
|
||||
const year = time.getFullYear();
|
||||
const month = time.getMonth();
|
||||
const day = time.getDate();
|
||||
const hours24 = time.getHours();
|
||||
const hours = hours24 % 12 === 0 ? 12 : hours24 % 12;
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
const milliseconds = time.getMilliseconds();
|
||||
const dd = (t: number) => `0${t}`.slice(-2);
|
||||
const map: { [key: string]: string | number } = {
|
||||
YYYY: year,
|
||||
MM: dd(month + 1),
|
||||
MMM: local.value.months[month],
|
||||
MMMM: local.value.monthsHead[month],
|
||||
M: month + 1,
|
||||
DD: dd(day),
|
||||
D: day,
|
||||
HH: dd(hours24),
|
||||
H: hours24,
|
||||
hh: dd(hours),
|
||||
h: hours,
|
||||
mm: dd(minutes),
|
||||
m: minutes,
|
||||
ss: dd(seconds),
|
||||
s: seconds,
|
||||
S: milliseconds,
|
||||
};
|
||||
return (format || props.format).replace(
|
||||
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
|
||||
(str: string) => map[str]
|
||||
);
|
||||
};
|
||||
const classObj: any = {};
|
||||
let flag = false;
|
||||
if (format === "YYYY") {
|
||||
flag = year === state.year;
|
||||
} else if (format === "YYYYMM") {
|
||||
flag = month === state.month;
|
||||
} else {
|
||||
flag = tf(props.value, format) === tf(time, format);
|
||||
}
|
||||
classObj[`${state.pre}-date`] = true;
|
||||
classObj[`${state.pre}-date-disabled`] =
|
||||
(props.right && t < start.value) || props.disabledDate(time, format);
|
||||
classObj[`${state.pre}-date-on`] =
|
||||
(props.left && t > start.value) || (props.right && t < end.value);
|
||||
classObj[`${state.pre}-date-selected`] = flag;
|
||||
return classObj;
|
||||
};
|
||||
const nm = () => {
|
||||
if (state.month < 11) {
|
||||
state.month++;
|
||||
} else {
|
||||
state.month = 0;
|
||||
state.year++;
|
||||
}
|
||||
};
|
||||
const pm = () => {
|
||||
if (state.month > 0) {
|
||||
state.month--;
|
||||
} else {
|
||||
state.month = 11;
|
||||
state.year--;
|
||||
}
|
||||
};
|
||||
const is = (e: any) => {
|
||||
return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1;
|
||||
};
|
||||
const ok = (info: any) => {
|
||||
let year = "";
|
||||
let month = "";
|
||||
let day = "";
|
||||
info && info.n && nm();
|
||||
info && info.p && pm();
|
||||
if (info === "h") {
|
||||
if (props.value) {
|
||||
const time = get(props.value);
|
||||
year = time.year;
|
||||
month = time.month;
|
||||
}
|
||||
} else if (info === "m" || info === "y") {
|
||||
day = "1";
|
||||
}
|
||||
const _time: Date = new Date(
|
||||
year ? Number(year) : state.year,
|
||||
month ? Number(month) : state.month,
|
||||
day ? Number(day) : state.day,
|
||||
state.hour,
|
||||
state.minute,
|
||||
state.second
|
||||
);
|
||||
if (props.left && Math.floor(_time.getTime() / 1000) > end.value) {
|
||||
emit("setDates", _time);
|
||||
}
|
||||
emit("input", _time);
|
||||
ok(info === "h");
|
||||
};
|
||||
onMounted(() => {
|
||||
const is = (c: string) => props.format.indexOf(c) !== -1;
|
||||
if (is("s") && is("m") && (is("h") || is("H"))) {
|
||||
state.m = "H";
|
||||
} else if (is("D")) {
|
||||
state.m = "D";
|
||||
} else if (is("M")) {
|
||||
state.m = "M";
|
||||
state.showMonths = true;
|
||||
} else if (is("Y")) {
|
||||
state.m = "Y";
|
||||
state.showYears = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.calendar {
|
||||
float: left;
|
||||
user-select: none;
|
||||
color: #3d444f;
|
||||
}
|
||||
.calendar + .calendar {
|
||||
border-left: solid 1px #eaeaea;
|
||||
margin-left: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.calendar-head {
|
||||
line-height: 34px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.calendar-head a {
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
padding: 0 5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.calendar-head a:hover {
|
||||
color: #3f97e3;
|
||||
}
|
||||
|
||||
.calendar-head .calendar-year-select,
|
||||
.calendar-head .calendar-month-select {
|
||||
font-size: 12px;
|
||||
padding: 0 2px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.calendar-prev-decade-btn,
|
||||
.calendar-prev-year-btn {
|
||||
left: 6px;
|
||||
}
|
||||
|
||||
.calendar-prev-month-btn {
|
||||
left: 24px;
|
||||
}
|
||||
|
||||
.calendar-next-decade-btn,
|
||||
.calendar-next-year-btn {
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
.calendar-next-month-btn {
|
||||
right: 24px;
|
||||
}
|
||||
.calendar-next-month-btn .middle,
|
||||
.calendar-prev-month-btn .middle {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.calendar-body {
|
||||
position: relative;
|
||||
width: 196px;
|
||||
height: 196px;
|
||||
}
|
||||
|
||||
.calendar-days {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.calendar-week,
|
||||
.calendar-date {
|
||||
font-weight: normal;
|
||||
width: 14.28%;
|
||||
height: 14.28%;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.calendar-week:before,
|
||||
.calendar-date:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.calendar-date {
|
||||
cursor: pointer;
|
||||
line-height: 29px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.calendar-date-out {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.calendar-date:hover,
|
||||
.calendar-date-on {
|
||||
color: #3f97e3;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.calendar-date-selected,
|
||||
.calendar-date-selected:hover {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
border-radius: 14px;
|
||||
background: #3f97e3;
|
||||
}
|
||||
|
||||
.calendar-date-disabled {
|
||||
cursor: not-allowed !important;
|
||||
color: #ccc !important;
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
.calendar-foot {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.calendar-hour {
|
||||
display: inline-block;
|
||||
border: 1px solid #e6e5e5;
|
||||
color: #9e9e9e;
|
||||
}
|
||||
|
||||
.calendar-hour a {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.calendar-hour a:hover,
|
||||
.calendar-hour a.on {
|
||||
color: #3f97e3;
|
||||
}
|
||||
|
||||
.calendar-years,
|
||||
.calendar-months,
|
||||
.calendar-hours,
|
||||
.calendar-minutes,
|
||||
.calendar-seconds {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.calendar-months a {
|
||||
width: 33.33%;
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
.calendar-years a {
|
||||
width: 33.33%;
|
||||
height: 25%;
|
||||
}
|
||||
|
||||
.calendar-overflow {
|
||||
overflow-x: scroll;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* .calendar-hours a {
|
||||
width: 20%;
|
||||
height: 20%;
|
||||
}
|
||||
|
||||
.calendar-minutes a,
|
||||
.calendar-seconds a {
|
||||
width: 16.66%;
|
||||
height: 10%;
|
||||
} */
|
||||
|
||||
.calendar-title {
|
||||
margin-top: -30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
69
src/components/Icon.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<svg
|
||||
class="icon"
|
||||
:class="{
|
||||
sm: size === 'sm',
|
||||
middle: size === 'middle',
|
||||
lg: size === 'lg',
|
||||
xl: size === 'xl',
|
||||
logo: size === 'logo',
|
||||
loading: loading,
|
||||
}"
|
||||
>
|
||||
<use :xlink:href="`#${iconName}`"></use>
|
||||
</svg>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
import "@/assets/icons/index";
|
||||
defineProps({
|
||||
iconName: { type: String, default: "" },
|
||||
size: { type: String, default: "sm" },
|
||||
loading: { type: Boolean, default: false },
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
fill: currentColor;
|
||||
&.sm {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
&.middle {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
&.lg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
&.loading {
|
||||
animation: loading 1.5s linear infinite;
|
||||
}
|
||||
&.logo {
|
||||
height: 30px;
|
||||
width: 110px;
|
||||
}
|
||||
&.xl {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
570
src/components/TimePicker.vue
Executable file
@@ -0,0 +1,570 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div
|
||||
class="datepicker cp"
|
||||
:class="{
|
||||
'datepicker-range': range,
|
||||
datepicker__clearable: clearable && text && !disabled,
|
||||
}"
|
||||
ref="datepicker"
|
||||
>
|
||||
<input
|
||||
class="cp"
|
||||
readonly
|
||||
:value="text"
|
||||
:class="[show ? 'focus' : '', inputClass]"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:name="name"
|
||||
v-if="type !== 'inline'"
|
||||
/>
|
||||
<a class="datepicker-close" @click.stop="cls"></a>
|
||||
<transition name="datepicker-anim">
|
||||
<div
|
||||
class="datepicker-popup"
|
||||
:class="[
|
||||
popupClass,
|
||||
{ 'datepicker-inline': type === 'inline' },
|
||||
position,
|
||||
]"
|
||||
tabindex="-1"
|
||||
v-if="show || type === 'inline'"
|
||||
>
|
||||
<template v-if="range">
|
||||
<div class="datepicker-popup__sidebar">
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('quarter')"
|
||||
>
|
||||
{{ local.quarterHourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('half')"
|
||||
>
|
||||
{{ local.halfHourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('hour')"
|
||||
>
|
||||
{{ local.hourCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('day')"
|
||||
>
|
||||
{{ local.dayCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('week')"
|
||||
>
|
||||
{{ local.weekCutTip }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="datepicker-popup__shortcut"
|
||||
@click="quickPick('month')"
|
||||
>
|
||||
{{ local.monthCutTip }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="datepicker-popup__body">
|
||||
<DateCalendar
|
||||
v-model="dates[0]"
|
||||
:value="dates[0]"
|
||||
:dates="dates"
|
||||
:left="true"
|
||||
:disabledDate="disabledDate"
|
||||
:format="format"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
<DateCalendar
|
||||
v-model="dates[1]"
|
||||
:value="dates[1]"
|
||||
:dates="dates"
|
||||
:right="true"
|
||||
:disabledDate="disabledDate"
|
||||
:format="format"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<DateCalendar
|
||||
v-model="dates[0]"
|
||||
:value="dates[0]"
|
||||
:disabledDate="disabledDate"
|
||||
:dates="dates"
|
||||
:format="format"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
</template>
|
||||
<div v-if="showButtons" class="datepicker__buttons">
|
||||
<button
|
||||
@click.prevent.stop="cancel"
|
||||
class="datepicker__button-cancel"
|
||||
>
|
||||
{{ local.cancelTip }}
|
||||
</button>
|
||||
<button
|
||||
@click.prevent.stop="submit"
|
||||
class="datepicker__button-select"
|
||||
>
|
||||
{{ local.submitTip }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineProps,
|
||||
ref,
|
||||
computed,
|
||||
defineEmits,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DateCalendar from "./DateCalendar.vue";
|
||||
const datepicker = ref(null);
|
||||
const { t } = useI18n();
|
||||
const show = ref<boolean>(false);
|
||||
const dates = ref<Date[]>([]);
|
||||
const props = defineProps({
|
||||
position: { type: String, default: "bottom" },
|
||||
name: [String],
|
||||
inputClass: [String],
|
||||
popupClass: [String],
|
||||
value: [Date, Array, String],
|
||||
disabled: [Boolean],
|
||||
type: {
|
||||
type: String,
|
||||
default: "normal",
|
||||
},
|
||||
rangeSeparator: {
|
||||
type: String,
|
||||
default: "~",
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: [String],
|
||||
disabledDate: {
|
||||
type: Function,
|
||||
default: () => false,
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: "YYYY-MM-DD",
|
||||
},
|
||||
showButtons: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dateRangeSelect: [Function],
|
||||
});
|
||||
const emit = defineEmits(["clear", "input", "confirm", "cancel"]);
|
||||
const local = computed(() => {
|
||||
return {
|
||||
dow: 1, // Monday is the first day of the week
|
||||
hourTip: t("hourTip"), // tip of select hour
|
||||
minuteTip: t("minuteTip"), // tip of select minute
|
||||
secondTip: t("secondTip"), // tip of select second
|
||||
yearSuffix: t("yearSuffix"), // format of head
|
||||
monthsHead: t("monthsHead").split("_"), // months of head
|
||||
months: t("months").split("_"), // months of panel
|
||||
weeks: t("weeks").split("_"), // weeks
|
||||
cancelTip: t("cancel"), // default text for cancel button
|
||||
submitTip: t("confirm"), // default text for submit button
|
||||
quarterHourCutTip: t("quarterHourCutTip"),
|
||||
halfHourCutTip: t("halfHourCutTip"),
|
||||
hourCutTip: t("hourCutTip"),
|
||||
dayCutTip: t("dayCutTip"),
|
||||
weekCutTip: t("weekCutTip"),
|
||||
monthCutTip: t("monthCutTip"),
|
||||
};
|
||||
});
|
||||
const tf = (time: Date, format?: any): string => {
|
||||
const year = time.getFullYear();
|
||||
const month = time.getMonth();
|
||||
const day = time.getDate();
|
||||
const hours24 = time.getHours();
|
||||
const hours = hours24 % 12 === 0 ? 12 : hours24 % 12;
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
const milliseconds = time.getMilliseconds();
|
||||
const dd = (t: number) => `0${t}`.slice(-2);
|
||||
const map: { [key: string]: string | number } = {
|
||||
YYYY: year,
|
||||
MM: dd(month + 1),
|
||||
MMM: local.value.months[month],
|
||||
MMMM: local.value.monthsHead[month],
|
||||
M: month + 1,
|
||||
DD: dd(day),
|
||||
D: day,
|
||||
HH: dd(hours24),
|
||||
H: hours24,
|
||||
hh: dd(hours),
|
||||
h: hours,
|
||||
mm: dd(minutes),
|
||||
m: minutes,
|
||||
ss: dd(seconds),
|
||||
s: seconds,
|
||||
S: milliseconds,
|
||||
};
|
||||
return (format || props.format).replace(
|
||||
/Y+|M+|D+|H+|h+|m+|s+|S+/g,
|
||||
(str: string) => map[str]
|
||||
);
|
||||
};
|
||||
const range = computed(() => {
|
||||
return dates.value.length === 2;
|
||||
});
|
||||
const text = computed(() => {
|
||||
const val = props.value;
|
||||
const txt = dates.value
|
||||
.map((date) => tf(date))
|
||||
.join(` ${props.rangeSeparator} `);
|
||||
if (Array.isArray(val)) {
|
||||
return val.length > 1 ? txt : "";
|
||||
}
|
||||
return val ? txt : "";
|
||||
});
|
||||
const get = () => {
|
||||
return Array.isArray(props.value) ? dates.value : dates.value[0];
|
||||
};
|
||||
const cls = () => {
|
||||
emit("clear");
|
||||
emit("input", range.value ? [] : "");
|
||||
};
|
||||
const vi = (val: any) => {
|
||||
if (Array.isArray(val)) {
|
||||
return val.length > 1
|
||||
? val.map((item) => new Date(item))
|
||||
: [new Date(), new Date()];
|
||||
}
|
||||
return val ? [new Date(val)] : [new Date()];
|
||||
};
|
||||
const ok = (leaveOpened: boolean) => {
|
||||
emit("input", get());
|
||||
!leaveOpened &&
|
||||
!props.showButtons &&
|
||||
setTimeout(() => {
|
||||
show.value = range.value;
|
||||
});
|
||||
};
|
||||
const setDates = (d: Date) => {
|
||||
dates.value[1] = d;
|
||||
};
|
||||
const dc = (e: any) => {
|
||||
show.value = (datepicker.value as any).contains(e.target) && !props.disabled;
|
||||
};
|
||||
const quickPick = (type: string) => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
switch (type) {
|
||||
case "quarter":
|
||||
start.setTime(start.getTime() - 60 * 15 * 1000); //15 mins
|
||||
break;
|
||||
case "half":
|
||||
start.setTime(start.getTime() - 60 * 30 * 1000); //30 mins
|
||||
break;
|
||||
case "hour":
|
||||
start.setTime(start.getTime() - 3600 * 1000); //1 hour
|
||||
break;
|
||||
case "day":
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24); //1 day
|
||||
break;
|
||||
case "week":
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); //1 week
|
||||
break;
|
||||
case "month":
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); //1 month
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dates.value = [start, end];
|
||||
emit("input", get());
|
||||
};
|
||||
const submit = () => {
|
||||
emit("confirm", get());
|
||||
show.value = false;
|
||||
};
|
||||
const cancel = () => {
|
||||
emit("cancel");
|
||||
show.value = false;
|
||||
};
|
||||
onMounted(() => {
|
||||
dates.value = vi(props.value);
|
||||
document.addEventListener("click", dc, true);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("click", dc, true);
|
||||
});
|
||||
watch(
|
||||
() => props.value,
|
||||
(val: unknown) => {
|
||||
dates.value = vi(val);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.datepicker {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.datepicker-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
color: #515a6ecc;
|
||||
}
|
||||
|
||||
.datepicker-close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 34px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datepicker-close:before {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
text-align: center;
|
||||
background: #ccc;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
background: #ccc
|
||||
url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3IDciIHdpZHRoPSI3IiBoZWlnaHQ9IjciPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01LjU4LDVsMi44LTIuODFBLjQxLjQxLDAsMSwwLDcuOCwxLjZMNSw0LjQxLDIuMiwxLjZhLjQxLjQxLDAsMCwwLS41OC41OGgwTDQuNDIsNSwxLjYyLDcuOGEuNDEuNDEsMCwwLDAsLjU4LjU4TDUsNS41OCw3LjgsOC4zOWEuNDEuNDEsMCwwLDAsLjU4LS41OGgwWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEuNSAtMS40OCkiIHN0eWxlPSJmaWxsOiNmZmYiLz48L3N2Zz4NCg==")
|
||||
no-repeat 50% 50%;
|
||||
}
|
||||
|
||||
.datepicker__clearable:hover:before {
|
||||
display: none;
|
||||
}
|
||||
.datepicker__clearable:hover .datepicker-close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.datepicker-close:hover:before {
|
||||
background-color: #afafaf;
|
||||
}
|
||||
|
||||
.datepicker > input {
|
||||
color: inherit;
|
||||
// transition: all 200ms ease;
|
||||
border-radius: 4px;
|
||||
border: 0;
|
||||
background: none;
|
||||
height: 28px;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
padding: 0 5px;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
font-family: "Monaco";
|
||||
letter-spacing: -0.7px;
|
||||
}
|
||||
|
||||
// .datepicker > input.focus {
|
||||
// border-color: #3f97e3;
|
||||
// -webkit-box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
|
||||
// box-shadow: 0 0 5px rgba(59, 180, 242, 0.3);
|
||||
// }
|
||||
|
||||
.datepicker > input:disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: #ebebe4;
|
||||
border-color: #e5e5e5;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.datepicker-popup {
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
transition: all 200ms ease;
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
font-size: 12px;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
|
||||
margin-top: 2px;
|
||||
outline: 0;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
z-index: 999;
|
||||
&.top {
|
||||
bottom: 30px;
|
||||
right: 0;
|
||||
transform-origin: center bottom;
|
||||
}
|
||||
&.bottom {
|
||||
top: 30px;
|
||||
right: 0;
|
||||
transform-origin: center top;
|
||||
}
|
||||
&.left {
|
||||
top: 30px;
|
||||
transform-origin: center top;
|
||||
}
|
||||
&.right {
|
||||
right: -80px;
|
||||
top: 30px;
|
||||
transform-origin: center top;
|
||||
}
|
||||
&__sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
border-right: solid 1px #eaeaea;
|
||||
}
|
||||
&__shortcut {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
line-height: 34px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: left;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
&:hover {
|
||||
color: #3f97e3;
|
||||
}
|
||||
}
|
||||
&__body {
|
||||
margin-left: 100px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-inline {
|
||||
position: relative;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.datepicker-range {
|
||||
min-width: 238px;
|
||||
}
|
||||
|
||||
.datepicker-range .datepicker-popup {
|
||||
width: 520px;
|
||||
}
|
||||
|
||||
.datepicker-bottom {
|
||||
float: left;
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.datepicker-btn {
|
||||
padding: 5px 10px;
|
||||
background: #3f97e3;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker-anim-enter-active {
|
||||
transform-origin: 0 0;
|
||||
animation: datepicker-anim-in 0.2s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
|
||||
.datepicker-anim-leave-active {
|
||||
transform-origin: 0 0;
|
||||
animation: datepicker-anim-out 0.2s cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
}
|
||||
|
||||
.datepicker__buttons {
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.datepicker__buttons button {
|
||||
display: inline-block;
|
||||
font-size: 13px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin: 10px 0 0 5px;
|
||||
padding: 5px 15px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.datepicker__buttons .datepicker__button-select {
|
||||
background: #3f97e3;
|
||||
}
|
||||
|
||||
.datepicker__buttons .datepicker__button-cancel {
|
||||
background: #666;
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes datepicker-anim-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
}
|
||||
</style>
|
30
src/components/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Icon from "./Icon.vue";
|
||||
import TimePicker from "./TimePicker.vue";
|
||||
import type { App } from "vue";
|
||||
|
||||
const components: { [key: string]: any } = { Icon, TimePicker };
|
||||
const componentsName: string[] = Object.keys(components);
|
||||
|
||||
export default {
|
||||
install: (vue: App): void => {
|
||||
componentsName.forEach((i) => {
|
||||
vue.component(i, components[i]);
|
||||
});
|
||||
},
|
||||
};
|
21
src/constants/data.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export enum TimeType {
|
||||
MINUTE_TIME = "MINUTE",
|
||||
HOUR_TIME = "HOUR",
|
||||
DAY_TIME = "DAY",
|
||||
}
|
28
src/graph/fragments/global.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const OAPTimeInfo = {
|
||||
query: `
|
||||
getTimeInfo {
|
||||
timezone
|
||||
currentTimestamp
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const OAPVersion = {
|
||||
query: `version { version }`,
|
||||
};
|
52
src/graph/index.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import axios, { AxiosPromise, AxiosResponse } from "axios";
|
||||
import { cancelToken } from "@/utils/cancelToken";
|
||||
import * as global from "./query/global";
|
||||
|
||||
const query: { [key: string]: string } = { ...global };
|
||||
class Graph {
|
||||
private queryData = "";
|
||||
public query(queryData: string) {
|
||||
this.queryData = queryData;
|
||||
return this;
|
||||
}
|
||||
public params(variablesData: unknown): AxiosPromise<void> {
|
||||
return axios
|
||||
.post(
|
||||
"/graphql",
|
||||
{
|
||||
query: query[this.queryData],
|
||||
variables: variablesData,
|
||||
},
|
||||
{ cancelToken: cancelToken() }
|
||||
)
|
||||
.then((res: AxiosResponse) => {
|
||||
if (res.data.errors) {
|
||||
res.data.errors = res.data.errors
|
||||
.map((e: { message: string }) => e.message)
|
||||
.join(" ");
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new Graph();
|
21
src/graph/query/global.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { OAPTimeInfo, OAPVersion } from "../fragments/global";
|
||||
|
||||
export const queryOAPTimeInfo = `query queryOAPTimeInfo {${OAPTimeInfo.query}}`;
|
||||
|
||||
export const queryOAPVersion = `query ${OAPVersion.query}`;
|
35
src/layout/Index.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="app-wrapper flex-h">
|
||||
<SideBar />
|
||||
<div class="main-container">
|
||||
<NavBar />
|
||||
<AppMain />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { AppMain, SideBar, NavBar } from "./components";
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.app-wrapper {
|
||||
height: 100%;
|
||||
}
|
||||
.main-container {
|
||||
flex-grow: 2;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
36
src/layout/components/AppMain.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from "vue-router";
|
||||
|
||||
const route = useRoute();
|
||||
const key = () => {
|
||||
return route.path;
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.app-main {
|
||||
height: calc(100% - 128px);
|
||||
}
|
||||
</style>
|
109
src/layout/components/NavBar.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="nav-bar flex-h" :class="{ dark: theme === 'dark' }">
|
||||
<div class="title">{{ t(pageName) }}</div>
|
||||
<div class="app-config">
|
||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||
<TimePicker
|
||||
v-model="time"
|
||||
:value="time"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
/>
|
||||
<span>
|
||||
UTC{{ utcHour >= 0 ? "+" : ""
|
||||
}}{{ `${appStore.utcHour}:${appStore.utcMin}` }}
|
||||
</span>
|
||||
<!-- <span @click="handleReload" title="refresh">
|
||||
<Icon icon="retry" :loading="auto" class="middle" />
|
||||
</span> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const route = useRoute();
|
||||
const pageName = ref<string>("");
|
||||
const timeRange = ref<number>(0);
|
||||
const theme = ref<string>("light");
|
||||
let utc = localStorage.getItem("utc") || "";
|
||||
if (!utc.includes(":")) {
|
||||
utc =
|
||||
(localStorage.getItem("utc") || -(new Date().getTimezoneOffset() / 60)) +
|
||||
":0";
|
||||
}
|
||||
const utcArr = (utc || "").split(":");
|
||||
const utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||
const utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||
|
||||
appStore.setUTC(utcHour, utcMin);
|
||||
console.log(route);
|
||||
const setConfig = (value: string) => {
|
||||
pageName.value = value || "";
|
||||
theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
||||
};
|
||||
const time = computed({
|
||||
get() {
|
||||
return [appStore.durationRow.start, appStore.durationRow.end];
|
||||
},
|
||||
set(val: Date[]) {
|
||||
timeRange.value =
|
||||
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
if (timeRange.value) {
|
||||
return;
|
||||
}
|
||||
appStore.setDuration(timeFormat(val));
|
||||
},
|
||||
});
|
||||
setConfig(String(route.meta.title));
|
||||
watch(
|
||||
() => route.meta.title,
|
||||
(title: unknown) => {
|
||||
setConfig(String(title));
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.nav-bar {
|
||||
padding: 5px 10px 5px 28px;
|
||||
text-align: left;
|
||||
justify-content: space-between;
|
||||
background-color: #fafbfc;
|
||||
border-bottom: 1px solid #dfe4e8;
|
||||
color: #222;
|
||||
}
|
||||
.nav-bar.dark {
|
||||
background-color: #333840;
|
||||
border-bottom: 1px solid #252a2f;
|
||||
color: #fafbfc;
|
||||
}
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
.nav-tabs {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
161
src/layout/components/SideBar.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="side-bar">
|
||||
<div :class="isCollapse ? 'logo-icon-collapse' : 'logo-icon'">
|
||||
<Icon
|
||||
:size="isCollapse ? 'xl' : 'logo'"
|
||||
:iconName="isCollapse ? 'logo' : 'logo-sw'"
|
||||
/>
|
||||
</div>
|
||||
<el-menu
|
||||
active-text-color="#448dfe"
|
||||
background-color="#252a2f"
|
||||
class="el-menu-vertical"
|
||||
default-active="0"
|
||||
text-color="#efefef"
|
||||
:unique-opened="true"
|
||||
:collapse="isCollapse"
|
||||
:style="{ border: 'none' }"
|
||||
>
|
||||
<template v-for="(menu, index) in routes" :key="index">
|
||||
<el-sub-menu :index="String(index)" v-if="menu.meta.hasGroup">
|
||||
<template #title>
|
||||
<router-link :to="menu.path" :exact="menu.meta.exact || false">
|
||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||
</el-icon>
|
||||
<span>{{ t(menu.meta.title) }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
<el-menu-item-group>
|
||||
<el-menu-item
|
||||
v-for="(m, idx) in filterMenus(menu.children)"
|
||||
:index="`${index}-${idx}`"
|
||||
:key="idx"
|
||||
>
|
||||
<router-link :to="m.path" :exact="m.meta.exact || false">
|
||||
<span>{{ t(m.meta.title) }}</span>
|
||||
</router-link>
|
||||
</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
</el-sub-menu>
|
||||
<el-menu-item :index="String(index)" @click="changePage(menu)" v-else>
|
||||
<el-icon class="menu-icons" :style="{ margin: '-10px 12px 0 0' }">
|
||||
<router-link :to="menu.children[0].path" :exact="menu.meta.exact">
|
||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||
</router-link>
|
||||
</el-icon>
|
||||
<template #title>
|
||||
<router-link :to="menu.children[0].path" :exact="menu.meta.exact">
|
||||
<span>{{ t(menu.meta.title) }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
<div
|
||||
class="menu-control"
|
||||
:class="isCollapse ? 'collapse' : ''"
|
||||
:style="{
|
||||
color: theme === 'light' ? '#eee' : '#252a2f',
|
||||
}"
|
||||
>
|
||||
<Icon
|
||||
size="middle"
|
||||
iconName="format_indent_decrease"
|
||||
@click="controlMenu"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useRouter, RouteRecordRaw, RouteRecordName } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import {
|
||||
ElMenu,
|
||||
ElMenuItem,
|
||||
ElSubMenu,
|
||||
ElMenuItemGroup,
|
||||
ElIcon,
|
||||
} from "element-plus";
|
||||
const { t } = useI18n();
|
||||
const name: RouteRecordName | null | undefined = String(
|
||||
useRouter().currentRoute.value.name
|
||||
);
|
||||
const theme = ["VirtualMachine", "Kubernetes"].includes(name || "")
|
||||
? ref("light")
|
||||
: ref("black");
|
||||
const routes = useRouter().options.routes;
|
||||
const isCollapse = ref(false);
|
||||
const controlMenu = () => {
|
||||
isCollapse.value = !isCollapse.value;
|
||||
};
|
||||
const changePage = (menu: RouteRecordRaw) => {
|
||||
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name))
|
||||
? "light"
|
||||
: "black";
|
||||
};
|
||||
const filterMenus = (menus: any[]) => {
|
||||
return menus.filter((d) => d.meta && !d.meta.notShow);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scope>
|
||||
.side-bar {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background: #252a2f;
|
||||
font-weight: bold;
|
||||
// box-shadow: 1px 5px 3px #888;
|
||||
}
|
||||
.el-menu-vertical:not(.el-menu--collapse) {
|
||||
width: 210px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.logo-icon-collapse {
|
||||
width: 65px;
|
||||
margin: 15px 0 30px 0;
|
||||
}
|
||||
.logo-icon {
|
||||
margin: 15px 0 30px 15px;
|
||||
width: 110px;
|
||||
}
|
||||
.el-sub-menu .el-icon {
|
||||
height: 26px;
|
||||
margin-right: 0;
|
||||
}
|
||||
.el-sub-menu__title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.menu-control {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 215px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s linear;
|
||||
z-index: 9999;
|
||||
color: #252a2f;
|
||||
}
|
||||
.menu-control.collapse {
|
||||
left: 70px;
|
||||
}
|
||||
.el-icon.el-sub-menu__icon-arrow {
|
||||
height: 12px;
|
||||
}
|
||||
</style>
|
19
src/layout/components/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { default as AppMain } from "./AppMain.vue";
|
||||
export { default as SideBar } from "./SideBar.vue";
|
||||
export { default as NavBar } from "./NavBar.vue";
|
38
src/locales/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createI18n } from "vue-i18n";
|
||||
import zh from "./lang/zh";
|
||||
import en from "./lang/en";
|
||||
|
||||
const messages = {
|
||||
en,
|
||||
zh,
|
||||
};
|
||||
|
||||
const savedLanguage = window.localStorage.getItem("lang");
|
||||
let language = navigator.language.split("-")[0];
|
||||
if (!savedLanguage) {
|
||||
window.localStorage.setItem("lang", language);
|
||||
}
|
||||
language = savedLanguage ? savedLanguage : language;
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: language,
|
||||
messages,
|
||||
});
|
||||
|
||||
export default i18n;
|
291
src/locales/lang/en.ts
Normal file
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const msg = {
|
||||
generalService: "General Service",
|
||||
services: "Services",
|
||||
traces: "Traces",
|
||||
metrics: "Metrics",
|
||||
serviceMesh: "Service Mesh",
|
||||
infrastructure: "Infrastructure",
|
||||
virtualMachine: "Virtual Machine",
|
||||
kubernetes: "Kubernetes",
|
||||
dashboardHome: "Dashboard Home",
|
||||
dashboardList: "Dashboard List",
|
||||
logs: "Logs",
|
||||
events: "Events",
|
||||
alerts: "Alerts",
|
||||
settings: "Settings",
|
||||
dashboards: "Dashboards",
|
||||
profiles: "Profiles",
|
||||
database: "Database",
|
||||
serviceName: "Service Name",
|
||||
technologies: "Technologies",
|
||||
generalServicePanel: "General Service Panel",
|
||||
health: "Health",
|
||||
groupName: "Group Name",
|
||||
topologies: "Topologies",
|
||||
dataPanel: "Data Panel",
|
||||
controlPanel: "Control Panel",
|
||||
eventList: "Event List",
|
||||
databasePanel: "Database Panel",
|
||||
meshServicePanel: "Service Panel",
|
||||
hourTip: "Select Hour",
|
||||
minuteTip: "Select Minute",
|
||||
secondTip: "Select Second",
|
||||
second: "s",
|
||||
yearSuffix: "Year",
|
||||
monthsHead: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||
months: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||
weeks: "Mon_Tue_Wed_Thu_Fir_Sat_Sun",
|
||||
hello: "Hello",
|
||||
helloMessage: "Welcome Back, Apache SkyWalking APM System !",
|
||||
username: "Username",
|
||||
password: "Password",
|
||||
title: "Title",
|
||||
width: "Width",
|
||||
height: "Height",
|
||||
login: "Login Now",
|
||||
signout: "Sign Out",
|
||||
dashboard: "Dashboard",
|
||||
topology: "Topology",
|
||||
trace: "Trace",
|
||||
alarm: "Alarm",
|
||||
event: "Event",
|
||||
auto: "Auto",
|
||||
reload: "Reload",
|
||||
usermode: "User Mode",
|
||||
editmode: "Edit Mode",
|
||||
currentService: "Current Service",
|
||||
currentEndpoint: "Current Endpoint",
|
||||
currentInstance: "Current Instance",
|
||||
currentVersion: "Current Version",
|
||||
currentPage: "Current Page",
|
||||
version: "Version",
|
||||
page: "Page",
|
||||
currentDatabase: "Current Database",
|
||||
templateConfig: "Template Configuration",
|
||||
copy: "Copy",
|
||||
reset: "Reset",
|
||||
apply: "Apply",
|
||||
createTemplate: "Create Template",
|
||||
templateType: "Template Type",
|
||||
templateName: "Template Name",
|
||||
template: "Template",
|
||||
confirm: "Confirm",
|
||||
cancel: "Cancel",
|
||||
createTab: "Create Tab",
|
||||
tabName: "Tab Name",
|
||||
nouse: "No Use",
|
||||
allServices: "All Services",
|
||||
serviceDetail: "Service Detail",
|
||||
detectPoint: "Detect Point",
|
||||
callType: "Call Type",
|
||||
server: "Server",
|
||||
client: "Client",
|
||||
name: "Name",
|
||||
types: "Types",
|
||||
cpm: "Cpm",
|
||||
sla: "SLA",
|
||||
latency: "Latency",
|
||||
avgResponseTime: "Avg Response Time ( ms )",
|
||||
avgThroughput: "Load (CPM - calls per minute)",
|
||||
avgSLA: "Successful Rate ( % )",
|
||||
all: "All",
|
||||
success: "Success",
|
||||
error: "Error",
|
||||
service: "Service",
|
||||
instance: "Instance",
|
||||
endpoints: "Endpoints",
|
||||
cache: "Cache",
|
||||
global: "Global",
|
||||
serviceendpoint: "ServiceEndpoint",
|
||||
serviceinstance: "ServiceInstance",
|
||||
databaseaccess: "DatabaseAccess",
|
||||
servicerelation: "ServiceRelation",
|
||||
serviceinstancerelation: "ServiceInstanceRelation",
|
||||
endpointrelation: "EndpointRelation",
|
||||
status: "Status",
|
||||
endpointName: "Endpoint Name",
|
||||
search: "Search",
|
||||
clear: "Clear",
|
||||
more: "More",
|
||||
traceID: "Trace ID",
|
||||
range: "Range",
|
||||
timeRange: "Time Range",
|
||||
duration: "Duration",
|
||||
startTime: "Start Time",
|
||||
start: "Start",
|
||||
spans: "Spans",
|
||||
spanInfo: "Span Info",
|
||||
spanType: "Span Type",
|
||||
time: "Time",
|
||||
tags: "Tags",
|
||||
component: "Component",
|
||||
table: "Table",
|
||||
list: "List",
|
||||
tree: "Tree",
|
||||
filterScope: "Filter Scope",
|
||||
searchKeyword: "Search Keyword",
|
||||
quarterHourCutTip: "Last 15 mins",
|
||||
halfHourCutTip: "Last 30 mins",
|
||||
hourCutTip: "Last 1 hour",
|
||||
dayCutTip: "Last 1 day",
|
||||
weekCutTip: "Last 1 week",
|
||||
monthCutTip: "Last 1 month",
|
||||
serverZone: "Server Zone",
|
||||
percentResponse: "Response Time Percentile ( ms )",
|
||||
exportImage: "Export image",
|
||||
queryData: "Query",
|
||||
previousService: "Previous Service",
|
||||
nextService: "Next Service",
|
||||
object: "Object",
|
||||
ShowInstanceDependency: "Show Instance Dependency",
|
||||
InstanceDependencyTitle: "Service Instance Dependency",
|
||||
profile: "Profile",
|
||||
newTask: "New Task",
|
||||
monitorTime: "Monitor Time",
|
||||
monitorDuration: "Monitor Duration",
|
||||
minThreshold: "Min Duration Threshold",
|
||||
dumpPeriod: "Dump Period",
|
||||
createTask: "Create Task",
|
||||
maxSamplingCount: "Max Sampling Count",
|
||||
analyze: "Analyze",
|
||||
noData: "No Data",
|
||||
taskInfo: "Task Information",
|
||||
task: "Task",
|
||||
operationType: "Operation Type",
|
||||
operationTime: "Operation Time",
|
||||
taskView: "View Task",
|
||||
includeChildren: "Include Children",
|
||||
excludeChildren: "Exclude Children",
|
||||
view: "View",
|
||||
timeTips: "Time interval cannot exceed 60 days",
|
||||
standardAPM: "Standard",
|
||||
entityType: "Entity type",
|
||||
maxItemNum: "Max number of Item",
|
||||
independentSelector: "Selectors",
|
||||
unknownMetrics: "Unknown Metrics",
|
||||
labels: "Labels",
|
||||
aggregation: "Data Calculation",
|
||||
unit: "Unit",
|
||||
labelsIndex: "Label Subscript",
|
||||
parentService: "Parent Service",
|
||||
isParentService: "Set Parent Service",
|
||||
noneParentService: "No Parent Service",
|
||||
serviceGroup: "Service Group",
|
||||
endpointFilter: "Endpoint Filter",
|
||||
editConfig: "Edit Config",
|
||||
databaseView: "Database",
|
||||
browserView: "Browser",
|
||||
metricsView: "NOC - Network Operation Center",
|
||||
sortOrder: "Sort Order",
|
||||
descendOrder: "Descend Order",
|
||||
increaseOrder: "Increase Order",
|
||||
defaultOrder: "Default Order",
|
||||
chartType: "Chart Type",
|
||||
currentDepth: "Current Depth",
|
||||
traceTagsTip: `Only tags defined in the core/default/searchableTracesTags are searchable.
|
||||
Check more details on the Configuration Vocabulary page`,
|
||||
tagsLink: "Configuration Vocabulary page",
|
||||
addTag: "Please input a tag",
|
||||
log: "Log",
|
||||
logCategory: "Log Category",
|
||||
errorCatalog: "Error Catalog",
|
||||
logDetail: "Log Detail ",
|
||||
timeReload: "Notice: The time interval must be greater than 0",
|
||||
errorInfo: "Error Info",
|
||||
stack: "Stack",
|
||||
serviceVersion: "Service Version",
|
||||
errorPage: "Error Page",
|
||||
category: "Category",
|
||||
grade: "Grade",
|
||||
relatedTraceLogs: "Related Logs",
|
||||
setConditions: "More Conditions",
|
||||
metricName: "Metric Name",
|
||||
keywordsOfContent: "Keys Of Content",
|
||||
excludingKeywordsOfContent: "Exclude Keys Of Content",
|
||||
return: "Return",
|
||||
isError: "Error",
|
||||
contentType: "Content Type",
|
||||
content: "Content",
|
||||
viewLogs: "View Logs",
|
||||
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
||||
Check more details on the Configuration Vocabulary page`,
|
||||
keywordsOfContentLogTips:
|
||||
"Current storage of SkyWalking OAP server does not support this.",
|
||||
setEvent: "Set Event",
|
||||
instanceAttributes: "Instance Attributes",
|
||||
serviceEvents: "Service Events",
|
||||
select: "Select",
|
||||
eventID: "Event ID",
|
||||
eventName: "Event Name",
|
||||
endTime: "End Time",
|
||||
instanceEvents: "Instance Events",
|
||||
endpointEvents: "Endpoint Events",
|
||||
enableEvents: "Enable Events",
|
||||
disableEvents: "Disable Events",
|
||||
eventSeries: "Events Series",
|
||||
eventsType: "Event Type",
|
||||
eventsMessage: "Event Message",
|
||||
eventsParameters: "Event Parameters",
|
||||
eventDetail: "Event Detail",
|
||||
value: "Value",
|
||||
tableHeader: "Header Names",
|
||||
tableValues: "Table Values",
|
||||
show: "Show",
|
||||
hide: "Hide",
|
||||
statistics: "Statistics",
|
||||
message: "Message",
|
||||
tooltipsContent: "Tooltip Content",
|
||||
alarmDetail: "Alarm Detail",
|
||||
scope: "Scope",
|
||||
destService: "Destination Service",
|
||||
destServiceInstance: "Destination Service Instance",
|
||||
eventSource: "Event Source",
|
||||
modalTitle: "Inspection",
|
||||
selectRedirectPage: "Do you want to inspect Traces or Logs of %s service?",
|
||||
logAnalysis: "Log Analysis Language",
|
||||
logDataBody: "The content of the log",
|
||||
addType: "Please input a type",
|
||||
traceContext: "Logs with trace context",
|
||||
traceSegmentId: "Trace Segment ID",
|
||||
spanId: "Span ID",
|
||||
inputTraceSegmentId: "Please input the trace segment ID",
|
||||
inputSpanId: "Please input the span ID",
|
||||
inputTraceId: "Please input the trace ID",
|
||||
dsl: "Script input for LAL",
|
||||
logContentType: "The type of the log content",
|
||||
logRespContent: "Log Content",
|
||||
analysis: "Analysis",
|
||||
waitLoading: "Loading",
|
||||
dslEmpty: "Script input of LAL should not be empty",
|
||||
logContentEmpty: "The content of the log should not be empty.",
|
||||
debug: "Debug",
|
||||
addTraceID: "Please input a trace ID",
|
||||
addKeywordsOfContent: "Please input a keyword of content",
|
||||
addExcludingKeywordsOfContent: "Please input a keyword of excluding content",
|
||||
noticeTag: "Please press enter after inputting a tag.",
|
||||
conditionNotice:
|
||||
"Notice: Please press enter after inputting a tag, key of content, exclude key of content.",
|
||||
cacheModalTitle: "Clear cache reminder",
|
||||
yes: "Yes",
|
||||
no: "No",
|
||||
cacheReminderContent:
|
||||
"SkyWalking detected dashboard template updates, do you want to update?",
|
||||
language: "Language",
|
||||
};
|
||||
export default msg;
|
287
src/locales/lang/zh.ts
Normal file
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const msg = {
|
||||
generalService: "普通服务",
|
||||
services: "服务",
|
||||
traces: "跟踪",
|
||||
metrics: "指标",
|
||||
serviceMesh: "服务网格",
|
||||
infrastructure: "基础结构",
|
||||
virtualMachine: "虚拟机",
|
||||
kubernetes: "Kubernetes",
|
||||
dashboardHome: "仪表盘首页",
|
||||
dashboardList: "仪表盘列表",
|
||||
log: "日志",
|
||||
events: "事件",
|
||||
alerts: "警告",
|
||||
settings: "设置",
|
||||
dashboards: "仪表盘",
|
||||
profiles: "性能剖析",
|
||||
database: "数据库",
|
||||
serviceName: "服务名称",
|
||||
technologies: "技术",
|
||||
health: "健康",
|
||||
groupName: "群名称",
|
||||
generalServicePanel: "普通服务面板",
|
||||
topologies: "拓扑图",
|
||||
dataPanel: "数据面板",
|
||||
controlPanel: "控制面板",
|
||||
eventList: "事件列表",
|
||||
databasePanel: "数据库面板",
|
||||
meshServicePanel: "服务面板",
|
||||
hourTip: "选择小时",
|
||||
minuteTip: "选择分钟",
|
||||
secondTip: "选择秒数",
|
||||
second: "秒",
|
||||
yearSuffix: "年",
|
||||
monthsHead: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月",
|
||||
months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月",
|
||||
weeks: "一_二_三_四_五_六_日",
|
||||
hello: "你好",
|
||||
helloMessage: "欢迎来到, Apache SkyWalking APM 系统 !",
|
||||
username: "用户名",
|
||||
password: "密码",
|
||||
title: "标题",
|
||||
width: "宽度",
|
||||
height: "高度",
|
||||
login: "登录",
|
||||
signout: "登出",
|
||||
topology: "拓扑图",
|
||||
trace: "追踪",
|
||||
alarm: "告警",
|
||||
event: "事件",
|
||||
auto: "自动",
|
||||
reload: "刷新",
|
||||
usermode: "用户模式",
|
||||
editmode: "编辑模式",
|
||||
currentService: "当前服务",
|
||||
currentEndpoint: "当前端点",
|
||||
currentInstance: "当前实例",
|
||||
currentVersion: "当前版本",
|
||||
currentPage: "当前页面",
|
||||
version: "版本",
|
||||
page: "页面",
|
||||
currentDatabase: "当前数据库",
|
||||
templateConfig: "模版配置",
|
||||
copy: "拷贝",
|
||||
reset: "重制",
|
||||
apply: "应用",
|
||||
createTemplate: "创建模板",
|
||||
templateType: "模板类型",
|
||||
templateName: "模板名称",
|
||||
template: "模版",
|
||||
confirm: "确定",
|
||||
cancel: "取消",
|
||||
createTab: "创建分页",
|
||||
tabName: "分页名",
|
||||
nouse: "不使用",
|
||||
allServices: "所有服务",
|
||||
serviceDetail: "服务详情",
|
||||
detectPoint: "侦察端",
|
||||
callType: "调用类型",
|
||||
server: "服务端",
|
||||
client: "客户端",
|
||||
name: "名称",
|
||||
types: "类型",
|
||||
cpm: "每分钟请求量",
|
||||
sla: "SLA",
|
||||
latency: "延迟",
|
||||
avgResponseTime: "平均响应时间",
|
||||
avgThroughput: "平均吞吐量",
|
||||
avgSLA: "平均SLA",
|
||||
all: "全部",
|
||||
success: "成功",
|
||||
error: "失败",
|
||||
service: "服务",
|
||||
instance: "实例",
|
||||
endpoints: "端点",
|
||||
cache: "存储器",
|
||||
global: "全局",
|
||||
serviceendpoint: "服务端点",
|
||||
serviceinstance: "服务实例",
|
||||
databaseaccess: "数据库存取",
|
||||
servicerelation: "服务关系",
|
||||
serviceinstancerelation: "服务实例关系",
|
||||
endpointrelation: "服务端点关系",
|
||||
status: "状态",
|
||||
endpointName: "端点名称",
|
||||
search: "搜索",
|
||||
clear: "清空",
|
||||
more: "更多",
|
||||
traceID: "追踪ID",
|
||||
range: "范围",
|
||||
timeRange: "时间范围",
|
||||
duration: "持续时间",
|
||||
startTime: "开始时间",
|
||||
start: "起始点",
|
||||
spans: "跨度",
|
||||
spanInfo: "跨度信息",
|
||||
spanType: "跨度类型",
|
||||
time: "时间",
|
||||
tags: "标记",
|
||||
logs: "日志",
|
||||
component: "组件",
|
||||
table: "表格",
|
||||
list: "列表",
|
||||
tree: "树结构",
|
||||
filterScope: "过滤范围",
|
||||
searchKeyword: "关键字搜索",
|
||||
quarterHourCutTip: "最近15分钟",
|
||||
halfHourCutTip: "最近30分钟",
|
||||
hourCutTip: "最近1小时",
|
||||
dayCutTip: "最近1天",
|
||||
weekCutTip: "最近1周",
|
||||
monthCutTip: "最近1月",
|
||||
serverZone: "服务器时区",
|
||||
percentResponse: "百分比响应",
|
||||
exportImage: "导出为图片",
|
||||
queryData: "数据查询",
|
||||
previousService: "上一个服务",
|
||||
nextService: "下一个服务",
|
||||
object: "粒度",
|
||||
ShowInstanceDependency: "展示实例依赖",
|
||||
InstanceDependencyTitle: "实例依赖",
|
||||
profile: "性能剖析",
|
||||
newTask: "新建任务",
|
||||
monitorTime: "监控时间",
|
||||
monitorDuration: "监控持续时间",
|
||||
minThreshold: "起始监控时间",
|
||||
dumpPeriod: "监控间隔",
|
||||
createTask: "新建任务",
|
||||
maxSamplingCount: "最大采样数",
|
||||
analyze: "分析",
|
||||
noData: "数据为空",
|
||||
taskInfo: "任务详情",
|
||||
task: "任务",
|
||||
operationType: "操作类型",
|
||||
operationTime: "操作时间",
|
||||
taskView: "查看任务详情",
|
||||
includeChildren: "包含子部分",
|
||||
excludeChildren: "不包含子部分",
|
||||
view: "查看",
|
||||
timeTips: "时间区间不能超过60天",
|
||||
standardAPM: "标准APM",
|
||||
entityType: "实体类型",
|
||||
maxItemNum: "最多条目数",
|
||||
independentSelector: "独立选择器",
|
||||
unknownMetrics: "未知指标",
|
||||
labels: "标签",
|
||||
aggregation: "数据计算",
|
||||
unit: "单位",
|
||||
labelsIndex: "标签下标",
|
||||
parentService: "父级服务",
|
||||
isParentService: "设置父服务",
|
||||
noneParentService: "不设置父服务",
|
||||
serviceGroup: "服务组",
|
||||
endpointFilter: "端点过滤器",
|
||||
editConfig: "编辑",
|
||||
databaseView: "数据库视图",
|
||||
browserView: "浏览器视图",
|
||||
metricsView: "大屏视图",
|
||||
sortOrder: "排序方式",
|
||||
descendOrder: "递减顺序",
|
||||
increaseOrder: "递增顺序",
|
||||
defaultOrder: "默认顺序",
|
||||
chartType: "图表类型",
|
||||
currentDepth: "当前深度",
|
||||
traceTagsTip:
|
||||
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
||||
tagsLink: "配置词汇页",
|
||||
addTag: "请添加标签",
|
||||
logCategory: "日志类别",
|
||||
errorCatalog: "错误类目",
|
||||
logDetail: "日志详情",
|
||||
timeReload: "注意:时间间隔必须大于0",
|
||||
errorInfo: "错误信息",
|
||||
stack: "堆栈",
|
||||
serviceVersion: "服务版本",
|
||||
errorPage: "错误页面",
|
||||
category: "类别",
|
||||
grade: "等级",
|
||||
relatedTraceLogs: "相关的日志",
|
||||
setConditions: "更多条件",
|
||||
metricName: "指标名称",
|
||||
keywordsOfContent: "内容关键词",
|
||||
excludingKeywordsOfContent: "内容不包含的关键词",
|
||||
return: "返回",
|
||||
isError: "错误",
|
||||
contentType: "内容类型",
|
||||
content: "内容",
|
||||
viewLogs: "查看日志",
|
||||
logsTagsTip:
|
||||
"只有core/default/searchableLogsTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
||||
keywordsOfContentLogTips: "SkyWalking OAP服务器的当前存储不支持此操作",
|
||||
setEvent: "设置事件",
|
||||
instanceAttributes: "实例属性",
|
||||
serviceEvents: "服务事件",
|
||||
select: "选择",
|
||||
eventID: "事件ID",
|
||||
eventName: "事件名称",
|
||||
endTime: "结束时间",
|
||||
instanceEvents: "实例事件",
|
||||
endpointEvents: "端点事件",
|
||||
enableEvents: "启动事件",
|
||||
disableEvents: "禁用事件",
|
||||
eventSeries: "事件系列",
|
||||
eventsType: "事件类型",
|
||||
eventsMessage: "事件消息",
|
||||
eventsParameters: "事件参数",
|
||||
eventDetail: "事件详情",
|
||||
value: "数值",
|
||||
tableHeader: "表头名称",
|
||||
tableValues: "表值",
|
||||
show: "展示",
|
||||
hide: "隐藏",
|
||||
statistics: "统计",
|
||||
message: "信息",
|
||||
tooltipsContent: "提示内容",
|
||||
alarmDetail: "警告详情",
|
||||
scope: "范围",
|
||||
destService: "终点服务",
|
||||
destServiceInstance: "终点实例",
|
||||
eventSource: "事件资源",
|
||||
modalTitle: "查看",
|
||||
selectRedirectPage: "查看 %s 服务的追踪或日志?",
|
||||
logAnalysis: "日志分析语言",
|
||||
logDataBody: "日志数据的内容",
|
||||
addType: "请输入一个类型",
|
||||
traceContext: "具有跟踪上下文的日志",
|
||||
traceSegmentId: "跟踪段ID",
|
||||
spanId: "跨度ID",
|
||||
inputTraceSegmentId: "请输入跟踪段ID",
|
||||
inputSpanId: "请输入跨度ID",
|
||||
inputTraceId: "请输入跟踪ID",
|
||||
dsl: "LAL的脚本输入",
|
||||
logContentType: "日志内容的类型",
|
||||
logRespContent: "日志内容",
|
||||
analysis: "分析",
|
||||
waitLoading: "加载中",
|
||||
dslEmpty: "LAL的脚本输入不应该是空",
|
||||
logContentEmpty: "日志数据的内容不应该是空。",
|
||||
debug: "调试",
|
||||
addTraceID: "请输入一个Trace ID",
|
||||
addKeywordsOfContent: "请输入一个内容关键词",
|
||||
addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词",
|
||||
noticeTag: "请输入一个标签之后回车",
|
||||
conditionNotice: "请输入一个标签、内容关键词或者内容不包含的关键词之后回车",
|
||||
cacheModalTitle: "清除缓存提醒",
|
||||
yes: "是的",
|
||||
no: "不",
|
||||
cacheReminderContent: "SkyWalking检测到仪表板模板更新,是否需要更新?",
|
||||
language: "语言",
|
||||
};
|
||||
export default msg;
|
32
src/main.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import { store } from "./store";
|
||||
import components from "@/components";
|
||||
import i18n from "./locales";
|
||||
import "element-plus/dist/index.css";
|
||||
import "./styles/lib.scss";
|
||||
import "./styles/reset.scss";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(components);
|
||||
app.use(i18n);
|
||||
app.use(store);
|
||||
app.use(router).mount("#app");
|
45
src/router/alert.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesAlert: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Alerts",
|
||||
meta: {
|
||||
title: "alerts",
|
||||
icon: "notification_important",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/alerts",
|
||||
name: "Alerts",
|
||||
meta: {
|
||||
title: "alerts",
|
||||
icon: "notification_important",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: () => import("@/views/Log.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
52
src/router/dashboard.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesDashboard: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
component: Layout,
|
||||
name: "Dashboard",
|
||||
meta: {
|
||||
title: "dashboards",
|
||||
icon: "dashboard_customize",
|
||||
hasGroup: true,
|
||||
exact: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/home",
|
||||
component: () => import("@/views/Service.vue"),
|
||||
name: "Home",
|
||||
meta: {
|
||||
title: "dashboardHome",
|
||||
exact: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/dashboard/list",
|
||||
component: () => import("@/views/Log.vue"),
|
||||
name: "List",
|
||||
meta: {
|
||||
title: "dashboardList",
|
||||
exact: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
53
src/router/database.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesDatabase: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Database",
|
||||
meta: {
|
||||
title: "database",
|
||||
icon: "epic",
|
||||
},
|
||||
redirect: "/database",
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/database",
|
||||
name: "Database",
|
||||
meta: {
|
||||
title: "database",
|
||||
headPath: "/database",
|
||||
exact: true,
|
||||
},
|
||||
component: () => import("@/views/Service.vue"),
|
||||
},
|
||||
{
|
||||
path: "/database/:id/:type",
|
||||
name: "DatabasePanel",
|
||||
meta: {
|
||||
title: "databasePanel",
|
||||
headPath: "/database",
|
||||
exact: true,
|
||||
},
|
||||
component: () => import("@/views/service/Panel.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
43
src/router/event.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesEvent: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Events",
|
||||
meta: {
|
||||
title: "events",
|
||||
icon: "av_timer",
|
||||
hasGroup: false,
|
||||
exact: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/events",
|
||||
name: "Events",
|
||||
meta: {
|
||||
title: "eventList",
|
||||
exact: false,
|
||||
},
|
||||
component: () => import("@/views/Log.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
55
src/router/generalService.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesGen: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "GeneralService",
|
||||
redirect: "/generalService",
|
||||
meta: {
|
||||
title: "generalService",
|
||||
icon: "chart",
|
||||
hasGroup: false,
|
||||
exact: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/generalService",
|
||||
name: "Services",
|
||||
meta: {
|
||||
title: "services",
|
||||
headPath: "/generalService/service",
|
||||
exact: true,
|
||||
},
|
||||
component: () => import("@/views/Service.vue"),
|
||||
},
|
||||
{
|
||||
path: "/generalService/service/:id/:type",
|
||||
name: "GeneralServicePanel",
|
||||
meta: {
|
||||
title: "generalServicePanel",
|
||||
headPath: "/generalService/service",
|
||||
exact: true,
|
||||
},
|
||||
component: () => import("@/views/service/Panel.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
46
src/router/index.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
|
||||
// import Layout from "@/layout/Index.vue";
|
||||
import { routesGen } from "./generalService";
|
||||
import { routesMesh } from "./serviceMesh";
|
||||
import { routesDatabase } from "./database";
|
||||
import { routesInfra } from "./infrastructure";
|
||||
import { routesDashboard } from "./dashboard";
|
||||
import { routesLog } from "./log";
|
||||
import { routesEvent } from "./event";
|
||||
import { routesAlert } from "./alert";
|
||||
import { routesSetting } from "./setting";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
...routesGen,
|
||||
...routesMesh,
|
||||
...routesDatabase,
|
||||
...routesInfra,
|
||||
...routesDashboard,
|
||||
...routesLog,
|
||||
...routesEvent,
|
||||
...routesAlert,
|
||||
...routesSetting,
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(process.env.BASE_URL),
|
||||
routes,
|
||||
});
|
||||
|
||||
export default router;
|
50
src/router/infrastructure.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesInfra: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Infrastructure",
|
||||
meta: {
|
||||
title: "infrastructure",
|
||||
icon: "scatter_plot",
|
||||
exact: true,
|
||||
hasGroup: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/infrastructure/vm",
|
||||
name: "VirtualMachine",
|
||||
meta: {
|
||||
title: "virtualMachine",
|
||||
},
|
||||
component: () => import("@/views/Infrastructure.vue"),
|
||||
},
|
||||
{
|
||||
path: "/infrastructure/k8s",
|
||||
name: "Kubernetes",
|
||||
meta: {
|
||||
title: "kubernetes",
|
||||
},
|
||||
component: () => import("@/views/Infrastructure.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
47
src/router/log.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesLog: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Logs",
|
||||
meta: {
|
||||
title: "logs",
|
||||
icon: "assignment",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/log",
|
||||
name: "Logs",
|
||||
meta: {
|
||||
title: "log",
|
||||
exact: false,
|
||||
},
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "about" */ "@/views/Log.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
94
src/router/serviceMesh.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesMesh: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "ServiceMesh",
|
||||
redirect: "/mesh/services",
|
||||
meta: {
|
||||
title: "serviceMesh",
|
||||
icon: "bar_chart",
|
||||
hasGroup: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/mesh/services",
|
||||
name: "MeshServices",
|
||||
meta: {
|
||||
title: "services",
|
||||
headPath: "/mesh/services",
|
||||
},
|
||||
component: () => import("@/views/Service.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/controlPanel",
|
||||
name: "ControlPanel",
|
||||
meta: {
|
||||
title: "controlPanel",
|
||||
headPath: "/mesh/controlPanel",
|
||||
},
|
||||
component: () => import("@/views/Service.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/dataPanel",
|
||||
name: "DataPanel",
|
||||
meta: {
|
||||
title: "dataPanel",
|
||||
headPath: "/mesh/dataPanel",
|
||||
},
|
||||
component: () => import("@/views/Service.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/services/:id/:type",
|
||||
name: "MeshServicePanel",
|
||||
meta: {
|
||||
title: "meshServicePanel",
|
||||
headPath: "/mesh/services",
|
||||
exact: true,
|
||||
notShow: true,
|
||||
},
|
||||
component: () => import("@/views/service/Panel.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/controlPanel/:id/:type",
|
||||
name: "MeshControlPanel",
|
||||
meta: {
|
||||
title: "controlPanel",
|
||||
headPath: "/mesh/controlPanel",
|
||||
exact: true,
|
||||
notShow: true,
|
||||
},
|
||||
component: () => import("@/views/service/Panel.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/dataPanel/:id/:type",
|
||||
name: "MeshDataPanel",
|
||||
meta: {
|
||||
title: "dataPanel",
|
||||
headPath: "/mesh/dataPanel",
|
||||
exact: true,
|
||||
notShow: true,
|
||||
},
|
||||
component: () => import("@/views/service/Panel.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
45
src/router/setting.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesSetting: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Settings",
|
||||
meta: {
|
||||
title: "settings",
|
||||
icon: "settings",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/settings",
|
||||
name: "Settings",
|
||||
meta: {
|
||||
title: "settings",
|
||||
icon: "settings",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: () => import("@/views/Settings.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
21
src/shims-vue.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
declare module "*.vue" {
|
||||
import { defineComponent } from "vue";
|
||||
const Component: ReturnType<typeof defineComponent>;
|
||||
export default Component;
|
||||
}
|
21
src/store/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createPinia } from "pinia";
|
||||
|
||||
const store = createPinia();
|
||||
|
||||
export { store };
|
108
src/store/modules/app/index.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { Duration, DurationTime } from "@/types/app";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import getDurationRow from "@/utils/dateTime";
|
||||
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
||||
|
||||
interface AppState {
|
||||
durationRow: any;
|
||||
utc: string;
|
||||
utcHour: number;
|
||||
utcMin: number;
|
||||
}
|
||||
|
||||
export const appStore = defineStore({
|
||||
id: "app",
|
||||
state: (): AppState => ({
|
||||
durationRow: getDurationRow(),
|
||||
utc: "",
|
||||
utcHour: 0,
|
||||
utcMin: 0,
|
||||
}),
|
||||
getters: {
|
||||
duration(): Duration {
|
||||
return {
|
||||
start: getLocalTime(this.utc, this.durationRow.start),
|
||||
end: getLocalTime(this.utc, this.durationRow.end),
|
||||
step: this.durationRow.step,
|
||||
};
|
||||
},
|
||||
durationTime(): DurationTime {
|
||||
return {
|
||||
start: dateFormatStep(this.duration.start, this.duration.step, true),
|
||||
end: dateFormatStep(this.duration.end, this.duration.step, true),
|
||||
step: this.duration.step,
|
||||
};
|
||||
},
|
||||
intervalTime(): string[] {
|
||||
let interval = 946080000000;
|
||||
switch (this.duration.step) {
|
||||
case "MINUTE":
|
||||
interval = 60000;
|
||||
break;
|
||||
case "HOUR":
|
||||
interval = 3600000;
|
||||
break;
|
||||
case "DAY":
|
||||
interval = 86400000;
|
||||
break;
|
||||
case "MONTH":
|
||||
interval =
|
||||
(this.duration.end.getTime() - this.duration.start.getTime()) /
|
||||
(this.duration.end.getFullYear() * 12 +
|
||||
this.duration.end.getMonth() -
|
||||
this.duration.start.getFullYear() * 12 -
|
||||
this.duration.start.getMonth());
|
||||
break;
|
||||
}
|
||||
const utcArr = this.utc.split(":");
|
||||
const utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||
const utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||
const utcSpace =
|
||||
(utcHour + new Date().getTimezoneOffset() / 60) * 3600000 +
|
||||
utcMin * 60000;
|
||||
const startUnix: number = this.duration.start.getTime();
|
||||
const endUnix: number = this.duration.end.getTime();
|
||||
const timeIntervals: string[] = [];
|
||||
for (let i = 0; i <= endUnix - startUnix; i += interval) {
|
||||
const temp: string = dateFormatTime(
|
||||
new Date(startUnix + i - utcSpace),
|
||||
this.duration.step
|
||||
);
|
||||
timeIntervals.push(temp);
|
||||
}
|
||||
return timeIntervals;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setDuration(data: Duration) {
|
||||
this.durationRow = data;
|
||||
},
|
||||
setUTC(utcHour: number, utcMin: number) {
|
||||
this.utcMin = utcMin;
|
||||
this.utcHour = utcHour;
|
||||
this.utc = `${utcHour}:${utcMin}`;
|
||||
localStorage.setItem("utc", this.utc);
|
||||
},
|
||||
},
|
||||
});
|
||||
export function useAppStoreWithOut() {
|
||||
return appStore(store);
|
||||
}
|
99
src/styles/lib.scss
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
.flex-v {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.flex-h {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.ell {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.cp {
|
||||
cursor: pointer;
|
||||
}
|
||||
.cm {
|
||||
cursor: move;
|
||||
}
|
||||
.auto {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
.green {
|
||||
color: #4caf50;
|
||||
}
|
||||
.red {
|
||||
color: #e54c17;
|
||||
}
|
||||
.blue {
|
||||
color: #448dfe;
|
||||
}
|
||||
.purple {
|
||||
color: #6e40aa;
|
||||
}
|
||||
.yellow {
|
||||
color: #fbb03b;
|
||||
}
|
||||
.grey {
|
||||
color: #a7aebb;
|
||||
}
|
||||
.bg-green {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
.bg-red {
|
||||
background-color: #e54c17;
|
||||
}
|
||||
.bg-blue {
|
||||
background-color: #448dfe;
|
||||
}
|
||||
.bg-purple {
|
||||
background-color: #6e40aa;
|
||||
}
|
||||
.bg-yellow {
|
||||
background-color: #fbb03b;
|
||||
}
|
||||
.bg-grey {
|
||||
background-color: #a7aebb;
|
||||
}
|
||||
.ml-5 {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.ml-10 {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.ml-15 {
|
||||
margin-left: 15px;
|
||||
}
|
||||
.ml-20 {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.mr-5 {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.mr-10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.mr-15 {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.mr-20 {
|
||||
margin-right: 20px;
|
||||
}
|
177
src/styles/reset.scss
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
font-size: 13px;
|
||||
color: #3d444f;
|
||||
font-family: 'Helvetica', 'Arial', 'Source Han Sans CN', 'Microsoft YaHei', 'sans-serif';
|
||||
text-rendering: optimizeLegibility;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
div,
|
||||
header,
|
||||
footer,
|
||||
nav,
|
||||
article,
|
||||
section,
|
||||
aside,
|
||||
label,
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
button,
|
||||
ul,
|
||||
ol,
|
||||
li,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
a,
|
||||
img {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
button {
|
||||
font-size: 100%;
|
||||
font-family: inherit;
|
||||
}
|
||||
h1 {
|
||||
font-size: 26px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 21px;
|
||||
}
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
hr {
|
||||
border-width: 0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
blockquote {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
padding-left: 1.2em;
|
||||
border-left: 4px solid #cacaca;
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: Consolas, Menlo, Courier, monospace;
|
||||
}
|
||||
/*webkit core*/
|
||||
.scroll_hide::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-track {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-track-piece {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-corner {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-webkit-scrollbar-resizer {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
/*o core*/
|
||||
.scroll_hide .-o-scrollbar {
|
||||
-moz-appearance: none !important;
|
||||
background: rgba(0, 255, 0, 0) !important;
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-track {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-track-piece {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-corner {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.scroll_hide::-o-scrollbar-resizer {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
/*IE10,IE11,IE12*/
|
||||
.scroll_hide {
|
||||
-ms-scroll-chaining: chained;
|
||||
-ms-overflow-style: none;
|
||||
-ms-content-zooming: zoom;
|
||||
-ms-scroll-rails: none;
|
||||
-ms-content-zoom-limit-min: 100%;
|
||||
-ms-content-zoom-limit-max: 500%;
|
||||
-ms-scroll-snap-points-x: snapList(100%, 200%, 300%, 400%, 500%);
|
||||
-ms-overflow-style: none;
|
||||
overflow: auto;
|
||||
}
|
||||
.scroll_bar_style::-webkit-scrollbar {
|
||||
width: 9px;
|
||||
height: 6px;
|
||||
}
|
||||
.scroll_bar_style::-webkit-scrollbar-track {
|
||||
background-color: #3d444f;
|
||||
}
|
||||
.scroll_bar_style::-webkit-scrollbar-thumb {
|
||||
border-radius: 5px;
|
||||
background: rgba(196, 200, 225, .2);
|
||||
}
|
114
src/type.d.ts
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type {
|
||||
ComponentRenderProxy,
|
||||
VNode,
|
||||
VNodeChild,
|
||||
ComponentPublicInstance,
|
||||
FunctionalComponent,
|
||||
PropType as VuePropType,
|
||||
} from "vue";
|
||||
|
||||
declare module "three";
|
||||
declare module "three-orbit-controls";
|
||||
declare module "element-plus";
|
||||
declare global {
|
||||
const __APP_INFO__: {
|
||||
pkg: {
|
||||
name: string;
|
||||
version: string;
|
||||
dependencies: Recordable<string>;
|
||||
devDependencies: Recordable<string>;
|
||||
};
|
||||
lastBuildTime: string;
|
||||
};
|
||||
|
||||
// vue
|
||||
declare type PropType<T> = VuePropType<T>;
|
||||
declare type VueNode = VNodeChild | JSX.Element;
|
||||
|
||||
export type Writable<T> = {
|
||||
-readonly [P in keyof T]: T[P];
|
||||
};
|
||||
|
||||
declare type Nullable<T> = T | null;
|
||||
declare type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
declare type Recordable<T = any> = Record<string, T>;
|
||||
declare type ReadonlyRecordable<T = any> = {
|
||||
readonly [key: string]: T;
|
||||
};
|
||||
declare type Indexable<T = any> = {
|
||||
[key: string]: T;
|
||||
};
|
||||
declare type DeepPartial<T> = {
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
};
|
||||
declare type TimeoutHandle = ReturnType<typeof setTimeout>;
|
||||
declare type IntervalHandle = ReturnType<typeof setInterval>;
|
||||
|
||||
declare interface ChangeEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
}
|
||||
|
||||
declare interface WheelEvent {
|
||||
path?: EventTarget[];
|
||||
}
|
||||
interface ImportMetaEnv extends ViteEnv {
|
||||
__: unknown;
|
||||
}
|
||||
|
||||
declare interface ViteEnv {
|
||||
VITE_PORT: number;
|
||||
VITE_USE_MOCK: boolean;
|
||||
VITE_USE_PWA: boolean;
|
||||
VITE_PUBLIC_PATH: string;
|
||||
VITE_PROXY: [string, string][];
|
||||
VITE_GLOB_APP_TITLE: string;
|
||||
VITE_GLOB_APP_SHORT_NAME: string;
|
||||
VITE_USE_CDN: boolean;
|
||||
VITE_DROP_CONSOLE: boolean;
|
||||
VITE_BUILD_COMPRESS: "gzip" | "brotli" | "none";
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean;
|
||||
VITE_LEGACY: boolean;
|
||||
VITE_USE_IMAGEMIN: boolean;
|
||||
VITE_GENERATE_UI: string;
|
||||
}
|
||||
|
||||
declare function parseInt(s: string | number, radix?: number): number;
|
||||
|
||||
declare function parseFloat(string: string | number): number;
|
||||
|
||||
namespace JSX {
|
||||
type Element = VNode;
|
||||
type ElementClass = ComponentRenderProxy;
|
||||
interface ElementAttributesProperty {
|
||||
$props: any;
|
||||
}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
}
|
||||
interface IntrinsicAttributes {
|
||||
[elem: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module "vue" {
|
||||
export type JSXComponent<Props = any> =
|
||||
| { new (): ComponentPublicInstance<Props> }
|
||||
| FunctionalComponent<Props>;
|
||||
}
|
30
src/types/app.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export interface Option {
|
||||
key: string | number;
|
||||
label: string;
|
||||
}
|
||||
export interface Duration {
|
||||
start: Date;
|
||||
end: Date;
|
||||
step: string;
|
||||
}
|
||||
export interface DurationTime {
|
||||
start: string;
|
||||
end: string;
|
||||
step: string;
|
||||
}
|
31
src/types/infrastructure.d.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export interface HexagonCreateParams {
|
||||
hexagonParam: number[];
|
||||
count: number;
|
||||
radius: number;
|
||||
origin?: number[];
|
||||
getShader?: any;
|
||||
}
|
||||
|
||||
export interface HexagonGeo {
|
||||
vertices: number[];
|
||||
normals: number[];
|
||||
insCenters: number[];
|
||||
indices: number[];
|
||||
origins: number[];
|
||||
}
|
24
src/utils/cancelToken.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import axios from "axios";
|
||||
const CancelToken = axios.CancelToken;
|
||||
|
||||
export const cancelToken = () =>
|
||||
new CancelToken(function executor(c) {
|
||||
const w = window as any;
|
||||
w.axiosCancel.push(c);
|
||||
});
|
101
src/utils/dateFormat.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export default function dateFormatStep(
|
||||
date: Date,
|
||||
step: string,
|
||||
monthDayDiff?: boolean
|
||||
): string {
|
||||
const year = date.getFullYear();
|
||||
const monthTemp = date.getMonth() + 1;
|
||||
let month = `${monthTemp}`;
|
||||
if (monthTemp < 10) {
|
||||
month = `0${monthTemp}`;
|
||||
}
|
||||
if (step === "MONTH" && monthDayDiff) {
|
||||
return `${year}-${month}`;
|
||||
}
|
||||
const dayTemp = date.getDate();
|
||||
let day = `${dayTemp}`;
|
||||
if (dayTemp < 10) {
|
||||
day = `0${dayTemp}`;
|
||||
}
|
||||
if (step === "DAY" || step === "MONTH") {
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
const hourTemp = date.getHours();
|
||||
let hour = `${hourTemp}`;
|
||||
if (hourTemp < 10) {
|
||||
hour = `0${hourTemp}`;
|
||||
}
|
||||
if (step === "HOUR") {
|
||||
return `${year}-${month}-${day} ${hour}`;
|
||||
}
|
||||
const minuteTemp = date.getMinutes();
|
||||
let minute = `${minuteTemp}`;
|
||||
if (minuteTemp < 10) {
|
||||
minute = `0${minuteTemp}`;
|
||||
}
|
||||
if (step === "MINUTE") {
|
||||
return `${year}-${month}-${day} ${hour}${minute}`;
|
||||
}
|
||||
const secondTemp = date.getSeconds();
|
||||
let second = `${secondTemp}`;
|
||||
if (secondTemp < 10) {
|
||||
second = `0${secondTemp}`;
|
||||
}
|
||||
if (step === "SECOND") {
|
||||
return `${year}-${month}-${day} ${hour}${minute}${second}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export const dateFormatTime = (date: Date, step: string): string => {
|
||||
const year = date.getFullYear();
|
||||
const monthTemp = date.getMonth() + 1;
|
||||
let month = `${monthTemp}`;
|
||||
if (monthTemp < 10) {
|
||||
month = `0${monthTemp}`;
|
||||
}
|
||||
if (step === "MONTH") {
|
||||
return `${year}-${month}`;
|
||||
}
|
||||
const dayTemp = date.getDate();
|
||||
let day = `${dayTemp}`;
|
||||
if (dayTemp < 10) {
|
||||
day = `0${dayTemp}`;
|
||||
}
|
||||
if (step === "DAY") {
|
||||
return `${month}-${day}`;
|
||||
}
|
||||
const hourTemp = date.getHours();
|
||||
let hour = `${hourTemp}`;
|
||||
if (hourTemp < 10) {
|
||||
hour = `0${hourTemp}`;
|
||||
}
|
||||
if (step === "HOUR") {
|
||||
return `${month}-${day} ${hour}`;
|
||||
}
|
||||
const minuteTemp = date.getMinutes();
|
||||
let minute = `${minuteTemp}`;
|
||||
if (minuteTemp < 10) {
|
||||
minute = `0${minuteTemp}`;
|
||||
}
|
||||
if (step === "MINUTE") {
|
||||
return `${hour}:${minute}\n${month}-${day}`;
|
||||
}
|
||||
return "";
|
||||
};
|
44
src/utils/dateTime.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Duration } from "@/types/app";
|
||||
import { TimeType } from "@/constants/data";
|
||||
|
||||
/**
|
||||
* init or generate durationRow Obj and save localStorage.
|
||||
*/
|
||||
const getDurationRow = (): Duration => {
|
||||
const durationRowString = localStorage.getItem("durationRow");
|
||||
let durationRow: Duration;
|
||||
if (durationRowString && durationRowString !== "") {
|
||||
durationRow = JSON.parse(durationRowString);
|
||||
durationRow = {
|
||||
start: new Date(durationRow.start),
|
||||
end: new Date(durationRow.end),
|
||||
step: durationRow.step,
|
||||
};
|
||||
} else {
|
||||
durationRow = {
|
||||
start: new Date(new Date().getTime() - 900000),
|
||||
end: new Date(),
|
||||
step: TimeType.MINUTE_TIME,
|
||||
};
|
||||
localStorage.setItem("durationRow", JSON.stringify(durationRow, null, 0));
|
||||
}
|
||||
return durationRow;
|
||||
};
|
||||
|
||||
export default getDurationRow;
|
56
src/utils/localtime.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import graph from "@/graph";
|
||||
import { AxiosResponse } from "axios";
|
||||
|
||||
const getLocalTime = (utc: string, time: Date): Date => {
|
||||
const utcArr = utc.split(":");
|
||||
const utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||
const utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||
const d = new Date(time);
|
||||
const len = d.getTime();
|
||||
const offset = d.getTimezoneOffset() * 60000;
|
||||
const utcTime = len + offset;
|
||||
return new Date(utcTime + 3600000 * utcHour + utcMin * 60000);
|
||||
};
|
||||
|
||||
const setTimezoneOffset = () => {
|
||||
window.localStorage.setItem(
|
||||
"utc",
|
||||
-(new Date().getTimezoneOffset() / 60) + ":0"
|
||||
);
|
||||
};
|
||||
|
||||
export const queryOAPTimeInfo = async (): Promise<void> => {
|
||||
let utc = window.localStorage.getItem("utc");
|
||||
if (!utc) {
|
||||
const res: AxiosResponse = await graph.query("queryOAPTimeInfo").params({});
|
||||
if (
|
||||
!res.data ||
|
||||
!res.data.data ||
|
||||
!res.data.data.getTimeInfo ||
|
||||
!res.data.data.getTimeInfo.timezone
|
||||
) {
|
||||
setTimezoneOffset();
|
||||
return;
|
||||
}
|
||||
utc = res.data.data.getTimeInfo.timezone / 100 + ":0";
|
||||
window.localStorage.setItem("utc", utc);
|
||||
}
|
||||
};
|
||||
|
||||
export default getLocalTime;
|
33
src/utils/timeFormat.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Duration } from "@/types/app";
|
||||
import { TimeType } from "@/constants/data";
|
||||
|
||||
const timeFormat = (time: Date[]): Duration => {
|
||||
let step: TimeType;
|
||||
const unix = Math.round(time[1].getTime()) - Math.round(time[0].getTime());
|
||||
if (unix <= 60 * 60 * 1000) {
|
||||
step = TimeType.MINUTE_TIME;
|
||||
} else if (unix <= 24 * 60 * 60 * 1000) {
|
||||
step = TimeType.HOUR_TIME;
|
||||
} else {
|
||||
step = TimeType.DAY_TIME;
|
||||
}
|
||||
return { start: time[0], end: time[1], step };
|
||||
};
|
||||
|
||||
export default timeFormat;
|
163
src/utils/vec2.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Vec2 extends Float32Array {
|
||||
constructor(v?: unknown, y?: unknown) {
|
||||
super(2);
|
||||
if (
|
||||
v instanceof Vec2 ||
|
||||
v instanceof Float32Array ||
|
||||
(v instanceof Array && v.length == 2)
|
||||
) {
|
||||
this[0] = v[0];
|
||||
this[1] = v[1];
|
||||
} else if (typeof v === "number" && typeof y === "number") {
|
||||
this[0] = v;
|
||||
this[1] = y;
|
||||
} else if (typeof v === "number") {
|
||||
this[0] = v;
|
||||
this[1] = v;
|
||||
}
|
||||
}
|
||||
xy(x: number, y: number): Vec2 {
|
||||
if (y != undefined) {
|
||||
this[0] = x;
|
||||
this[1] = y;
|
||||
} else this[0] = this[1] = x;
|
||||
return this;
|
||||
}
|
||||
get x(): number {
|
||||
return this[0];
|
||||
}
|
||||
set x(v: number) {
|
||||
this[0] = v;
|
||||
}
|
||||
get y(): number {
|
||||
return this[1];
|
||||
}
|
||||
set y(v: number) {
|
||||
this[1] = v;
|
||||
}
|
||||
len(): number {
|
||||
return Math.sqrt(this[0] * this[0] + this[1] * this[1]);
|
||||
}
|
||||
fromAdd(a: number[], b: number[]): Vec2 {
|
||||
this[0] = a[0] + b[0];
|
||||
this[1] = a[1] + b[1];
|
||||
return this;
|
||||
}
|
||||
fromSub(a: number[] | Vec2, b: number[] | Vec2): Vec2 {
|
||||
this[0] = a[0] - b[0];
|
||||
this[1] = a[1] - b[1];
|
||||
return this;
|
||||
}
|
||||
fromScale(a: number[] | Vec2, s: number): Vec2 {
|
||||
this[0] = a[0] * s;
|
||||
this[1] = a[1] * s;
|
||||
return this;
|
||||
}
|
||||
fromLerp(a: number[] | Vec2, b: number[] | Vec2, t: number): Vec2 {
|
||||
const tt = 1 - t;
|
||||
this[0] = a[0] * tt + b[0] * t;
|
||||
this[1] = a[1] * tt + b[1] * t;
|
||||
return this;
|
||||
}
|
||||
/** Used to get data from a flat buffer of vectors, useful when building geometery */
|
||||
fromBuf(ary: number[], idx: number): Vec2 {
|
||||
this[0] = ary[idx];
|
||||
this[1] = ary[idx + 1];
|
||||
return this;
|
||||
}
|
||||
/** Pust vector components onto an array, useful when building geometery */
|
||||
pushTo(ary: number[]): Vec2 {
|
||||
ary.push(this[0], this[1]);
|
||||
return this;
|
||||
}
|
||||
add(v: number[]): Vec2 {
|
||||
this[0] += v[0];
|
||||
this[1] += v[1];
|
||||
return this;
|
||||
}
|
||||
addRaw(x: number, y: number): Vec2 {
|
||||
this[0] += x;
|
||||
this[1] += y;
|
||||
return this;
|
||||
}
|
||||
sub(v: number[]): Vec2 {
|
||||
this[0] -= v[0];
|
||||
this[1] -= v[1];
|
||||
return this;
|
||||
}
|
||||
scale(v: number): Vec2 {
|
||||
this[0] *= v;
|
||||
this[1] *= v;
|
||||
return this;
|
||||
}
|
||||
norm(out?: number[] | Vec2): number[] | Vec2 | undefined {
|
||||
const mag = Math.sqrt(this[0] * this[0] + this[1] * this[1]);
|
||||
if (mag == 0) return this;
|
||||
out = out || this;
|
||||
out[0] = this[0] / mag;
|
||||
out[1] = this[1] / mag;
|
||||
return out;
|
||||
}
|
||||
perpCCW(): Vec2 {
|
||||
const x = this[0];
|
||||
this[0] = -this[1];
|
||||
this[1] = x;
|
||||
return this;
|
||||
}
|
||||
static add(a: number[], b: number[]): Vec2 {
|
||||
return new Vec2().fromAdd(a, b);
|
||||
}
|
||||
static sub(a: number[], b: number[]): Vec2 {
|
||||
return new Vec2().fromSub(a, b);
|
||||
}
|
||||
static scale(v: number[], s: number): Vec2 {
|
||||
return new Vec2().fromScale(v, s);
|
||||
}
|
||||
static lerp(v0: number[], v1: number[], t: number): Vec2 {
|
||||
return new Vec2().fromLerp(v0, v1, t);
|
||||
}
|
||||
static len(v0: Vec2, v1: Vec2): number {
|
||||
return Math.sqrt((v0[0] - v1[0]) ** 2 + (v0[1] - v1[1]) ** 2);
|
||||
}
|
||||
/** Create an Iterator Object that allows an easy way to loop a Float32Buffer
|
||||
* @example
|
||||
* let buf = new Float32Array( 2 * 10 );
|
||||
* for( let v of Vec3.bufIter( buf ) ){console.log( v )};
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
static bufIter(buf: number[]) {
|
||||
let i = 0;
|
||||
const result = { value: new Vec2(), done: false },
|
||||
len = buf.length,
|
||||
next = () => {
|
||||
if (i >= len) result.done = true;
|
||||
else {
|
||||
result.value.fromBuf(buf, i);
|
||||
i += 2;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
return {
|
||||
[Symbol.iterator]() {
|
||||
return { next };
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
export default Vec2;
|
177
src/utils/vec3.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Vec3 extends Float32Array {
|
||||
constructor(v?: unknown, y?: unknown, z?: unknown) {
|
||||
super(3);
|
||||
if (
|
||||
v instanceof Vec3 ||
|
||||
v instanceof Float32Array ||
|
||||
(v instanceof Array && v.length == 3)
|
||||
) {
|
||||
this[0] = v[0];
|
||||
this[1] = v[1];
|
||||
this[2] = v[2];
|
||||
} else if (
|
||||
typeof v === "number" &&
|
||||
typeof y === "number" &&
|
||||
typeof z === "number"
|
||||
) {
|
||||
this[0] = v;
|
||||
this[1] = y;
|
||||
this[2] = z;
|
||||
} else if (typeof v === "number") {
|
||||
this[0] = v;
|
||||
this[1] = v;
|
||||
this[2] = v;
|
||||
}
|
||||
}
|
||||
xyz(x: number, y: number, z: number): Vec3 {
|
||||
if (y != undefined && z != undefined) {
|
||||
this[0] = x;
|
||||
this[1] = y;
|
||||
this[2] = z;
|
||||
} else this[0] = this[1] = this[2] = x;
|
||||
return this;
|
||||
}
|
||||
get x(): number {
|
||||
return this[0];
|
||||
}
|
||||
set x(v: number) {
|
||||
this[0] = v;
|
||||
}
|
||||
get y(): number {
|
||||
return this[1];
|
||||
}
|
||||
set y(v: number) {
|
||||
this[1] = v;
|
||||
}
|
||||
get z(): number {
|
||||
return this[2];
|
||||
}
|
||||
set z(v: number) {
|
||||
this[2] = v;
|
||||
}
|
||||
|
||||
fromVec2(v: Vec3, useZ = false): Vec3 {
|
||||
this[0] = v[0];
|
||||
if (useZ) {
|
||||
this[1] = 0;
|
||||
this[2] = v[1];
|
||||
} else {
|
||||
this[1] = v[1];
|
||||
this[2] = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
norm(): Vec3 {
|
||||
let mag = Math.sqrt(this[0] ** 2 + this[1] ** 2 + this[2] ** 2);
|
||||
if (mag != 0) {
|
||||
mag = 1 / mag;
|
||||
this[0] *= mag;
|
||||
this[1] *= mag;
|
||||
this[2] *= mag;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/** Pust vector components onto an array, useful when building geometery */
|
||||
pushTo(ary: number[]): Vec3 {
|
||||
ary.push(this[0], this[1], this[2]);
|
||||
return this;
|
||||
}
|
||||
// INTERPOLATION SETTERS
|
||||
fromLerp(a: Vec3, b: Vec3, t: number): Vec3 {
|
||||
const ti = 1 - t; // Linear Interpolation : (1 - t) * v0 + t * v1;
|
||||
this[0] = a[0] * ti + b[0] * t;
|
||||
this[1] = a[1] * ti + b[1] * t;
|
||||
this[2] = a[2] * ti + b[2] * t;
|
||||
return this;
|
||||
}
|
||||
/** Add vector to current vector */
|
||||
add(a: Vec3 | number[]): Vec3 {
|
||||
this[0] += a[0];
|
||||
this[1] += a[1];
|
||||
this[2] += a[2];
|
||||
return this;
|
||||
}
|
||||
sub(v: Vec3 | number[]): Vec3 {
|
||||
this[0] -= v[0];
|
||||
this[1] -= v[1];
|
||||
this[2] -= v[2];
|
||||
return this;
|
||||
}
|
||||
scale(v: number): Vec3 {
|
||||
this[0] *= v;
|
||||
this[1] *= v;
|
||||
this[2] *= v;
|
||||
return this;
|
||||
}
|
||||
/** Scale a vector */
|
||||
fromScale(a: Vec3, s: number): Vec3 {
|
||||
this[0] = a[0] * s;
|
||||
this[1] = a[1] * s;
|
||||
this[2] = a[2] * s;
|
||||
return this;
|
||||
}
|
||||
/** Add two vectors together */
|
||||
fromAdd(a: Vec3, b: number[]): Vec3 {
|
||||
this[0] = a[0] + b[0];
|
||||
this[1] = a[1] + b[1];
|
||||
this[2] = a[2] + b[2];
|
||||
return this;
|
||||
}
|
||||
/** Subtract two vectors together */
|
||||
fromSub(a: number[], b: number[]): Vec3 {
|
||||
this[0] = a[0] - b[0];
|
||||
this[1] = a[1] - b[1];
|
||||
this[2] = a[2] - b[2];
|
||||
return this;
|
||||
}
|
||||
/** Copy in vector data */
|
||||
copy(v: any[] | Float32Array): Vec3 {
|
||||
this[0] = v[0];
|
||||
this[1] = v[1];
|
||||
this[2] = v[2];
|
||||
return this;
|
||||
}
|
||||
static add(a: Vec3, b: number[]): Vec3 {
|
||||
return new Vec3().fromAdd(a, b);
|
||||
}
|
||||
static sub(a: number[], b: number[]): Vec3 {
|
||||
return new Vec3().fromSub(a, b);
|
||||
}
|
||||
static scale(a: Vec3, s: number): Vec3 {
|
||||
return new Vec3().fromScale(a, s);
|
||||
}
|
||||
static norm(x: unknown, y: unknown, z: unknown): Vec3 {
|
||||
const rtn = new Vec3();
|
||||
if (
|
||||
x instanceof Vec3 ||
|
||||
x instanceof Float32Array ||
|
||||
(x instanceof Array && x.length == 3)
|
||||
) {
|
||||
rtn.copy(x);
|
||||
} else if (
|
||||
typeof x === "number" &&
|
||||
typeof y === "number" &&
|
||||
typeof z === "number"
|
||||
) {
|
||||
rtn.xyz(x, y, z);
|
||||
}
|
||||
return rtn.norm();
|
||||
}
|
||||
}
|
||||
export default Vec3;
|
29
src/views/Infrastructure.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="Infrastructure">
|
||||
<InfrastructureMap />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import InfrastructureMap from "./infrastructure/InfrastructureMap.vue";
|
||||
</script>
|
||||
<style scoped>
|
||||
.Infrastructure {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
23
src/views/Log.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="about">{{ props.msg }}</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
const props = defineProps({
|
||||
msg: String,
|
||||
});
|
||||
</script>
|
131
src/views/Service.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="service-table">
|
||||
<el-table :data="tableData" :span-method="objectSpanMethod" border>
|
||||
<el-table-column
|
||||
v-for="(h, index) in tableHeader"
|
||||
:label="t(h)"
|
||||
:key="h + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<router-link
|
||||
:to="`${state.path}/${scope.row.serviceName}/metrics`"
|
||||
v-if="h === tableHeader[1] && index !== 0"
|
||||
>
|
||||
<span class="service-name cp">{{ scope.row[h] }}</span>
|
||||
</router-link>
|
||||
<span v-else>{{ scope.row[h] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRoute } from "vue-router";
|
||||
import { ElTable, ElTableColumn } from "element-plus";
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const tableHeader = [
|
||||
"groupName",
|
||||
"serviceName",
|
||||
"types",
|
||||
"technologies",
|
||||
"endpoints",
|
||||
"health",
|
||||
];
|
||||
const tableData = [
|
||||
{
|
||||
endpoints: 2,
|
||||
groupName: "group 1",
|
||||
serviceName: "discount",
|
||||
types: "HTTP",
|
||||
health: true,
|
||||
technologies: "Spring Boot",
|
||||
},
|
||||
{
|
||||
endpoints: 3,
|
||||
groupName: "group 1",
|
||||
serviceName: "frontend",
|
||||
types: "HTTP",
|
||||
health: true,
|
||||
technologies: "Node.js",
|
||||
},
|
||||
{
|
||||
endpoints: 3,
|
||||
groupName: "group 2",
|
||||
serviceName: "web",
|
||||
types: "",
|
||||
health: true,
|
||||
technologies: "Nginx",
|
||||
},
|
||||
{
|
||||
endpoints: 3,
|
||||
groupName: "group 2",
|
||||
serviceName: "shipping",
|
||||
types: "HTTP",
|
||||
health: true,
|
||||
technologies: "JVM",
|
||||
},
|
||||
{
|
||||
endpoints: 3,
|
||||
groupName: "group 3",
|
||||
serviceName: "payment",
|
||||
types: "HTTP MESSAGING",
|
||||
health: true,
|
||||
technologies: "RabbitMQ Python",
|
||||
},
|
||||
];
|
||||
const state = reactive({
|
||||
path: route.meta.headPath,
|
||||
});
|
||||
const objectSpanMethod = (item: { columnIndex: number; rowIndex: number }) => {
|
||||
if (item.columnIndex === 0) {
|
||||
if (item.rowIndex % 2 === 0) {
|
||||
return {
|
||||
rowspan: 2,
|
||||
colspan: 1,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
rowspan: 0,
|
||||
colspan: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
watch(
|
||||
() => route.meta.headPath,
|
||||
(path: unknown) => {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
state.path = path;
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.service-name {
|
||||
color: #448edf;
|
||||
cursor: pointer;
|
||||
}
|
||||
.service-table {
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
201
src/views/Settings.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="settings">
|
||||
<!-- <div class="flex-h item">
|
||||
<span class="label">{{ t("version") }}</span>
|
||||
<span>{{ rocketbotGlobal.version }}</span>
|
||||
</div> -->
|
||||
<div class="flex-h item">
|
||||
<span class="label">{{ t("language") }}</span>
|
||||
<el-switch
|
||||
v-model="lang"
|
||||
:change="setLang"
|
||||
active-text="En"
|
||||
inactive-text="Zh"
|
||||
style="height: 25px"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-h item">
|
||||
<span class="label">{{ t("serverZone") }}</span>
|
||||
<div>
|
||||
<span>UTC</span>
|
||||
<span class="ml-5 mr-5">{{ utcHour >= 0 ? "+" : "" }}</span>
|
||||
<input
|
||||
type="number"
|
||||
v-model="utcHour"
|
||||
min="-12"
|
||||
max="14"
|
||||
class="utc-input"
|
||||
@change="setUTCHour"
|
||||
/>
|
||||
<span class="ml-5 mr-5">:</span>
|
||||
<span class="utc-min">{{ utcMin > 9 || utcMin === 0 ? null : 0 }}</span>
|
||||
<input
|
||||
type="number"
|
||||
v-model="utcMin"
|
||||
min="0"
|
||||
max="59"
|
||||
class="utc-input"
|
||||
@change="setUTCMin"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-h item">
|
||||
<span class="label">{{ t("auto") }}</span>
|
||||
<el-switch :change="handleAuto" style="height: 25px" />
|
||||
<div class="auto-time ml-5">
|
||||
<span class="auto-select">
|
||||
<input
|
||||
type="number"
|
||||
v-model="autoTime"
|
||||
@change="changeAutoTime"
|
||||
min="1"
|
||||
/>
|
||||
</span>
|
||||
{{ t("second") }}
|
||||
<i class="ml-10">{{ t("timeReload") }}</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import { ElSwitch } from "element-plus";
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const state = reactive<{ timer: any }>({
|
||||
timer: null,
|
||||
});
|
||||
const lang = ref<boolean>(locale.value === "zh" ? false : true);
|
||||
const autoTime = ref<number>(6);
|
||||
const auto = ref<boolean>(false);
|
||||
const appStore = useAppStoreWithOut();
|
||||
const utcArr = appStore.utc.split(":");
|
||||
const utcHour = ref<number>(isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]));
|
||||
const utcMin = ref<number>(isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]));
|
||||
|
||||
const handleReload = () => {
|
||||
const gap =
|
||||
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
appStore.setDuration(timeFormat(time));
|
||||
};
|
||||
const handleAuto = (status: boolean) => {
|
||||
if (autoTime.value < 1) {
|
||||
return;
|
||||
}
|
||||
auto.value = status;
|
||||
if (auto.value) {
|
||||
handleReload();
|
||||
state.timer = setInterval(handleReload, autoTime.value * 1000);
|
||||
} else {
|
||||
clearInterval(state.timer);
|
||||
}
|
||||
};
|
||||
const changeAutoTime = () => {
|
||||
if (autoTime.value < 1) {
|
||||
return;
|
||||
}
|
||||
clearInterval(state.timer);
|
||||
if (auto.value) {
|
||||
handleReload();
|
||||
state.timer = setInterval(handleReload, autoTime.value * 1000);
|
||||
}
|
||||
};
|
||||
const setLang = (): void => {
|
||||
if (lang.value) {
|
||||
locale.value = "en";
|
||||
window.localStorage.setItem("lang", "en");
|
||||
} else {
|
||||
locale.value = "zh";
|
||||
window.localStorage.setItem("lang", "zh");
|
||||
}
|
||||
};
|
||||
const setUTCHour = () => {
|
||||
if (utcHour.value < -12) {
|
||||
utcHour.value = -12;
|
||||
}
|
||||
if (utcHour.value > 14) {
|
||||
utcHour.value = 14;
|
||||
}
|
||||
if (isNaN(utcHour.value)) {
|
||||
utcHour.value = 0;
|
||||
}
|
||||
appStore.setUTC(utcHour.value, utcMin.value);
|
||||
};
|
||||
const setUTCMin = () => {
|
||||
if (utcMin.value < 0) {
|
||||
utcMin.value = 0;
|
||||
}
|
||||
if (utcMin.value > 59) {
|
||||
utcMin.value = 59;
|
||||
}
|
||||
if (isNaN(utcMin.value)) {
|
||||
utcMin.value = 0;
|
||||
}
|
||||
appStore.setUTC(utcHour.value, utcMin.value);
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.utc-input {
|
||||
color: inherit;
|
||||
background: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.utc-min {
|
||||
display: inline-block;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.auto-select {
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
padding: 1px;
|
||||
border-radius: 3px;
|
||||
|
||||
input {
|
||||
width: 38px;
|
||||
border-style: unset;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
.settings {
|
||||
color: #222;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
padding: 20px;
|
||||
.item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
input {
|
||||
outline: 0;
|
||||
width: 50px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
text-align: center;
|
||||
height: 25px;
|
||||
}
|
||||
.label {
|
||||
width: 100px;
|
||||
display: inline-block;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
339
src/views/infrastructure/InfrastructureMap.vue
Normal file
@@ -0,0 +1,339 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="infrastructure-box">
|
||||
<div ref="mapRef" class="map"></div>
|
||||
<div class="info-box" v-show="showInfo">
|
||||
{{ nodeTypes[type] }} Information
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import * as THREE from "three";
|
||||
import fac from "three-orbit-controls";
|
||||
import { Line2 } from "three/examples/jsm/lines/Line2";
|
||||
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
|
||||
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
|
||||
import { HexagonCreateParams } from "@/types/infrastructure";
|
||||
import HexagonPillar from "./geometry/hexagon-pillar";
|
||||
import { Layout } from "./geometry/hexagon-layout";
|
||||
import { NodeTypes } from "./data";
|
||||
|
||||
const animateCallbacks: Array<() => void> = [];
|
||||
const showInfo = ref<boolean>(false);
|
||||
const objSelected = ref<any>(null);
|
||||
const meshColors = ref([0xa1cffb, 0x333333, 0x333840, 0x999999]); //[0xa489b2, 0xf2bfd0, 0xf0eaea, 0xef6775, 0xfbc580];
|
||||
const nodeTypes = ref(NodeTypes);
|
||||
const type = ref<number>(0);
|
||||
const width = ref<number>(1920);
|
||||
const height = ref<number>(900);
|
||||
const mapRef = ref<HTMLDivElement | null>(null);
|
||||
let lineObj: any;
|
||||
let scene: any;
|
||||
let camera: any;
|
||||
let raycaster: any;
|
||||
let pointer: any;
|
||||
|
||||
onMounted(() => {
|
||||
if (mapRef.value) {
|
||||
init(mapRef.value);
|
||||
}
|
||||
window.addEventListener("click", onMouseClick, false);
|
||||
animate();
|
||||
});
|
||||
|
||||
function init(dom: HTMLDivElement): void {
|
||||
width.value = dom.offsetWidth;
|
||||
height.value = dom.offsetHeight + 74;
|
||||
camera = new THREE.PerspectiveCamera(
|
||||
45,
|
||||
width.value / height.value,
|
||||
1,
|
||||
10000
|
||||
);
|
||||
camera.position.set(0, 30, 140);
|
||||
scene = new THREE.Scene();
|
||||
let light = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
light.position.set(4, 10, 4);
|
||||
|
||||
scene.add(light);
|
||||
scene.add(new THREE.AmbientLight(0x404040));
|
||||
scene.background = new THREE.Color(0x333840);
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
antialias: true,
|
||||
alpha: true,
|
||||
});
|
||||
renderer.setSize(width.value, height.value);
|
||||
dom.appendChild(renderer.domElement);
|
||||
|
||||
const window = Window as any;
|
||||
const OrbitControls = fac(THREE);
|
||||
window.controls = new OrbitControls(camera, renderer.domElement);
|
||||
window.controls.enableZoom = true;
|
||||
window.controls.enablePan = true;
|
||||
|
||||
const helper = new THREE.GridHelper(10000, 40, 0x04002c, 0x04002c);
|
||||
helper.position.y = -1000;
|
||||
// this.scene.add(helper);
|
||||
const axis = new THREE.AxesHelper(15000);
|
||||
// this.scene.add(axis);
|
||||
// add mesh
|
||||
createInfrastructure();
|
||||
|
||||
raycaster = new THREE.Raycaster();
|
||||
pointer = new THREE.Vector2();
|
||||
animateCallbacks.push(() => {
|
||||
renderer.render(scene, camera);
|
||||
});
|
||||
}
|
||||
|
||||
function createInfrastructure() {
|
||||
//layer mesh
|
||||
const l = {
|
||||
hexagonParam: [27, 0.04, 5, 0.04, 0],
|
||||
count: 1,
|
||||
radius: 28, // layout hexagons radius
|
||||
};
|
||||
const [originVectors] = createHexagonLine(l, [0, 0, 0], 0);
|
||||
// group mesh
|
||||
const g: HexagonCreateParams = {
|
||||
hexagonParam: [8, 0.04, 5, 0.04, 0.01],
|
||||
count: 1,
|
||||
radius: 8.5,
|
||||
};
|
||||
const [gVecs] = createPillarMesh(g, originVectors, 1);
|
||||
// service mesh
|
||||
const s: HexagonCreateParams = {
|
||||
hexagonParam: [2, 0.04, 5, 0.04, 0.2],
|
||||
count: 1,
|
||||
radius: 2.2,
|
||||
};
|
||||
const [sVecs] = createPillarMesh(s, gVecs, 2);
|
||||
|
||||
// instance mesh
|
||||
const i: HexagonCreateParams = {
|
||||
hexagonParam: [0.2, 0.04, 5, 0.04, 0.3],
|
||||
count: 2,
|
||||
radius: 0.3,
|
||||
};
|
||||
createPillarMesh(i, sVecs, 3);
|
||||
}
|
||||
|
||||
function createHexagonLine(
|
||||
p: HexagonCreateParams,
|
||||
originVectors: number[],
|
||||
type: number
|
||||
) {
|
||||
lineObj = new THREE.Object3D();
|
||||
const centers: number[] = [];
|
||||
const geo = HexagonPillar.getVertices(false, ...p.hexagonParam);
|
||||
|
||||
for (let i = 0; i < originVectors.length / 3; i++) {
|
||||
const c = [originVectors[3 * i], originVectors[3 * i + 2]];
|
||||
const [origins] = hexGrid(p.count, p.radius, c);
|
||||
centers.push(...origins);
|
||||
}
|
||||
for (let c = 0; c < centers.length / 3; c++) {
|
||||
const vertices = [];
|
||||
for (let v = 0; v < geo.vertices.length; v++) {
|
||||
vertices.push(
|
||||
centers[3 * c] + geo.vertices[v].x,
|
||||
centers[3 * c + 1] + geo.vertices[v].y,
|
||||
centers[3 * c + 2] + geo.vertices[v].z
|
||||
);
|
||||
}
|
||||
const geometry = new LineGeometry().setPositions(vertices);
|
||||
geometry.setAttribute(
|
||||
"id",
|
||||
new THREE.BufferAttribute(new Int8Array([type]), 1)
|
||||
);
|
||||
const material = new LineMaterial({
|
||||
color: meshColors.value[type],
|
||||
linewidth: 4,
|
||||
// opacity: 0.2,
|
||||
dashed: false,
|
||||
});
|
||||
material.resolution.set(width.value, height.value);
|
||||
const line = new Line2(geometry, material);
|
||||
line.computeLineDistances();
|
||||
lineObj.add(line);
|
||||
}
|
||||
scene.add(lineObj);
|
||||
return [centers];
|
||||
}
|
||||
|
||||
function createPillarMesh(
|
||||
p: HexagonCreateParams,
|
||||
originVectors: number[],
|
||||
type: number
|
||||
) {
|
||||
const centers: number[] = [];
|
||||
const geo = HexagonPillar.get(false, ...p.hexagonParam);
|
||||
|
||||
for (let i = 0; i < originVectors.length / 3; i++) {
|
||||
const c = [originVectors[3 * i], originVectors[3 * i + 2]];
|
||||
const [origins] = hexGrid(p.count, p.radius, c);
|
||||
centers.push(...origins);
|
||||
}
|
||||
const hMat = new THREE.MeshStandardMaterial({
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
});
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setIndex(geo.indices);
|
||||
geometry.setAttribute(
|
||||
"position",
|
||||
new THREE.BufferAttribute(new Float32Array(geo.vertices), 3)
|
||||
);
|
||||
geometry.setAttribute(
|
||||
"normal",
|
||||
new THREE.BufferAttribute(new Float32Array(geo.normals), 3)
|
||||
);
|
||||
geometry.setAttribute(
|
||||
"type",
|
||||
new THREE.BufferAttribute(new Int8Array([type]), 1)
|
||||
);
|
||||
const mesh = new THREE.InstancedMesh(geometry, hMat, centers.length / 3);
|
||||
for (let c = 0; c < centers.length / 3; c++) {
|
||||
const matrix = new THREE.Matrix4();
|
||||
const color = new THREE.Color();
|
||||
color.setHex(meshColors.value[type]);
|
||||
for (let j = 0; j < geo.vertices.length / 3; j++) {
|
||||
matrix.setPosition(
|
||||
geo.vertices[3 * j] + centers[3 * c],
|
||||
geo.vertices[3 * j + 1] + centers[3 * c + 1],
|
||||
geo.vertices[3 * j + 2] + centers[3 * c + 2]
|
||||
);
|
||||
}
|
||||
mesh.setMatrixAt(c, matrix);
|
||||
mesh.setColorAt(c, color);
|
||||
}
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
scene.add(mesh);
|
||||
|
||||
return [centers];
|
||||
}
|
||||
|
||||
function hexGrid(n = 1, radius = 1, origin = [0, 0]) {
|
||||
let x, y, yn, p;
|
||||
const gLayout = new Layout(radius, origin);
|
||||
// const coord = [];
|
||||
const pos = [];
|
||||
// x = -1; n = 1.5
|
||||
for (x = -n; x <= n; x++) {
|
||||
y = Math.max(-n, -x - n); // 0
|
||||
yn = Math.min(n, -x + n); // 1
|
||||
// y = 0 yn = 1
|
||||
for (y; y <= yn; y++) {
|
||||
p = gLayout.axialToPixel(x, y);
|
||||
pos.push(p[0], 0, p[1]);
|
||||
// coord.push(x, y);
|
||||
}
|
||||
}
|
||||
return [pos];
|
||||
}
|
||||
|
||||
function onMouseClick(event: MouseEvent) {
|
||||
pointer.x = ((event.clientX - 210) / width.value) * 2 - 1;
|
||||
pointer.y = -((event.clientY - 0) / height.value) * 2 + 1;
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
let meshes = scene.children.filter((d: any) => d instanceof THREE.Mesh);
|
||||
meshes = [...meshes, ...lineObj.children];
|
||||
const intersects = raycaster.intersectObjects(meshes, true);
|
||||
const intersect = intersects[0];
|
||||
|
||||
if (objSelected.value) {
|
||||
for (const m of meshes) {
|
||||
if (m instanceof Line2) {
|
||||
m.material.color.setHex(meshColors.value[0]);
|
||||
m.material.needsUpdate = true;
|
||||
} else {
|
||||
const mType = m.geometry.getAttribute("type").array[0];
|
||||
m.setColorAt(
|
||||
objSelected.value.instanceId,
|
||||
new THREE.Color(meshColors.value[mType])
|
||||
);
|
||||
m.instanceColor.needsUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersect) {
|
||||
showInfo.value = true;
|
||||
if (intersect.object instanceof Line2) {
|
||||
intersect.object.material.color.setHex(0x73b3b9);
|
||||
objSelected.value = intersect;
|
||||
type.value = 0;
|
||||
intersect.object.material.needsUpdate = true;
|
||||
} else {
|
||||
intersect.object.setColorAt(
|
||||
intersect.instanceId,
|
||||
new THREE.Color(0x73b3b9)
|
||||
);
|
||||
intersect.object.instanceColor.needsUpdate = true;
|
||||
objSelected.value = intersect;
|
||||
type.value =
|
||||
objSelected.value.object.geometry.getAttribute("type").array[0];
|
||||
}
|
||||
} else {
|
||||
if (objSelected.value) {
|
||||
for (const m of meshes) {
|
||||
if (m instanceof Line2) {
|
||||
m.material.color.setHex(meshColors.value[0]);
|
||||
m.material.needsUpdate = true;
|
||||
} else {
|
||||
const mType = m.geometry.getAttribute("type").array[0];
|
||||
m.setColorAt(
|
||||
objSelected.value.instanceId,
|
||||
new THREE.Color(meshColors.value[mType])
|
||||
);
|
||||
m.instanceColor.needsUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
objSelected.value = null;
|
||||
type.value = NaN;
|
||||
showInfo.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function animate(): void {
|
||||
animateCallbacks.forEach((fn) => fn());
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.info-box {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
height: 700px;
|
||||
width: 300px;
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
}
|
||||
.infrastructure-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
23
src/views/infrastructure/data.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const NodeTypes = [
|
||||
"Layer",
|
||||
"Group",
|
||||
"Service",
|
||||
"Service Instance",
|
||||
"endpoint",
|
||||
];
|
144
src/views/infrastructure/geometry/hexagon-layout.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
class Orientation {
|
||||
public f0 = 0;
|
||||
public f1 = 0;
|
||||
public f2 = 0;
|
||||
public f3 = 0;
|
||||
public b0? = 0;
|
||||
public b1? = 0;
|
||||
public b2? = 0;
|
||||
public b3? = 0;
|
||||
public start_angle? = 0;
|
||||
constructor(
|
||||
f0: number,
|
||||
f1: number,
|
||||
f2: number,
|
||||
f3: number,
|
||||
b0: number,
|
||||
b1: number,
|
||||
b2: number,
|
||||
b3: number,
|
||||
start_angle: number
|
||||
) {
|
||||
this.f0 = f0;
|
||||
this.f1 = f1;
|
||||
this.f2 = f2;
|
||||
this.f3 = f3;
|
||||
this.b0 = b0;
|
||||
this.b1 = b1;
|
||||
this.b2 = b2;
|
||||
this.b3 = b3;
|
||||
this.start_angle = start_angle;
|
||||
}
|
||||
}
|
||||
|
||||
const SQRT3 = Math.sqrt(3.0);
|
||||
class Layout {
|
||||
static Pointy = new Orientation(
|
||||
SQRT3,
|
||||
SQRT3 / 2.0,
|
||||
0.0,
|
||||
3.0 / 2.0,
|
||||
SQRT3 / 3.0,
|
||||
-1.0 / 3.0,
|
||||
0.0,
|
||||
2.0 / 3.0,
|
||||
0.5
|
||||
);
|
||||
static Flat = new Orientation(
|
||||
3.0 / 2.0,
|
||||
0.0,
|
||||
SQRT3 / 2.0,
|
||||
SQRT3,
|
||||
2.0 / 3.0,
|
||||
0.0,
|
||||
-1.0 / 3.0,
|
||||
SQRT3 / 3.0,
|
||||
0.0
|
||||
);
|
||||
|
||||
static spacing(radius: number, isPointy = false): number[] {
|
||||
return isPointy
|
||||
? [SQRT3 * radius, 2 * radius * (3 / 4)]
|
||||
: [2 * radius * (3 / 4), SQRT3 * radius];
|
||||
}
|
||||
|
||||
private radius = 1;
|
||||
private orientation: Orientation = { f0: 0, f1: 0, f2: 0, f3: 0 };
|
||||
private origin = [0, 0];
|
||||
|
||||
constructor(radius: number, origin = [0, 0], orientation?: Orientation) {
|
||||
this.radius = radius; //Layout.spacing( radius, ( orientation === Layout.Pointy ) );
|
||||
this.orientation = orientation || Layout.Flat;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
// Same as HexToPixel, Except it takes raw coords instead of hex object.
|
||||
axialToPixel(ax: number, ay: number): number[] {
|
||||
const M = this.orientation;
|
||||
const x = (M.f0 * ax + M.f1 * ay) * this.radius;
|
||||
const y = (M.f2 * ax + M.f3 * ay) * this.radius;
|
||||
|
||||
return [x + this.origin[0], y + this.origin[1]];
|
||||
}
|
||||
|
||||
hexToPixel(h: { x: number; y: number }): number[] {
|
||||
const M = this.orientation;
|
||||
const x = (M.f0 * h.x + M.f1 * h.y) * this.radius;
|
||||
const y = (M.f2 * h.x + M.f3 * h.y) * this.radius;
|
||||
|
||||
return [x + this.origin[0], y + this.origin[1]];
|
||||
}
|
||||
}
|
||||
|
||||
class Hex extends Int16Array {
|
||||
constructor(x: number, y: number, z = null) {
|
||||
super(3);
|
||||
this.xyz(x, y, z);
|
||||
}
|
||||
|
||||
xyz(x: number, y: number, z: number | null = null): Hex {
|
||||
if (z == null) z = -x - y;
|
||||
if (x + y + z != 0) {
|
||||
console.log("Bad Axial Coordinate : : q %d r %d s %d", x, y, z);
|
||||
}
|
||||
|
||||
this[0] = x;
|
||||
this[1] = y;
|
||||
this[2] = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
get x(): number {
|
||||
return this[0];
|
||||
}
|
||||
get y(): number {
|
||||
return this[1];
|
||||
}
|
||||
get z(): number {
|
||||
return this[2];
|
||||
}
|
||||
|
||||
get len(): number {
|
||||
return Math.floor(
|
||||
(Math.abs(this[0]) + Math.abs(this[1]) + Math.abs(this[2])) / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { Hex, Orientation, Layout };
|
281
src/views/infrastructure/geometry/hexagon-pillar.ts
Normal file
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Vec3 from "@/utils/vec3";
|
||||
import Vec2 from "@/utils/vec2";
|
||||
|
||||
class HexagonPillar {
|
||||
static get(
|
||||
pointyUp = true,
|
||||
radius = 0.5,
|
||||
cornerScale = 0.2,
|
||||
cornerDiv = 3,
|
||||
capSize = 0.2,
|
||||
offsetHeight = 0.5
|
||||
): {
|
||||
vertices: number[];
|
||||
indices: number[];
|
||||
texcoord: number[];
|
||||
normals: number[];
|
||||
} {
|
||||
const rtn: {
|
||||
vertices: number[];
|
||||
indices: number[];
|
||||
texcoord: number[];
|
||||
normals: number[];
|
||||
} = {
|
||||
vertices: [],
|
||||
indices: [],
|
||||
texcoord: [],
|
||||
normals: [],
|
||||
};
|
||||
|
||||
let poly = createPolygon(radius, 6, pointyUp ? (30 * Math.PI) / 180 : 0); // Create Base Shape
|
||||
poly = polyBevel(poly, cornerScale, cornerDiv); // Round the Shape Corners
|
||||
// Base Layer
|
||||
toVec3(rtn, poly);
|
||||
const vertCnt = rtn.vertices.length / 3;
|
||||
// Starting layer for Cap.
|
||||
toVec3(rtn, poly, [0, offsetHeight, 0]);
|
||||
|
||||
// Extra Layers for Bevel
|
||||
polyCapBevel(rtn, poly, cornerDiv, capSize, [0, offsetHeight, 0]);
|
||||
const idxTip = rtn.vertices.length;
|
||||
|
||||
// Cap Center Point
|
||||
rtn.vertices.push(0, capSize + offsetHeight, 0);
|
||||
rtn.normals.push(0, 1, 0);
|
||||
|
||||
// Indices
|
||||
const idx = idxTip / 3;
|
||||
gridIndicesCol(rtn.indices, vertCnt, 2 + cornerDiv, 0, true, true);
|
||||
fanIndices(rtn.indices, idx, idx - vertCnt, idx - 1, true);
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
return rtn;
|
||||
}
|
||||
static getVertices(pointyUp = true, radius = 0.5): { vertices: Vec3[] } {
|
||||
const rtn = {
|
||||
vertices: [],
|
||||
normals: [],
|
||||
};
|
||||
|
||||
const poly = createPolygon(radius, 6, pointyUp ? (30 * Math.PI) / 180 : 0); // Create Base Shape
|
||||
toVec3(rtn, poly);
|
||||
const vertices = [];
|
||||
for (let i = 0; i < rtn.vertices.length / 3; i++) {
|
||||
vertices.push(
|
||||
new Vec3(
|
||||
rtn.vertices[i * 3],
|
||||
rtn.vertices[i * 3 + 1],
|
||||
rtn.vertices[i * 3 + 2]
|
||||
)
|
||||
);
|
||||
}
|
||||
vertices.push(new Vec3(rtn.vertices[0], rtn.vertices[1], rtn.vertices[2]));
|
||||
return { vertices };
|
||||
}
|
||||
}
|
||||
// Create the basic 2d polygon shape
|
||||
function createPolygon(radius: number, sides = 6, offset = 0) {
|
||||
const poly = [];
|
||||
let i, rad;
|
||||
for (i = 0; i < sides; i++) {
|
||||
rad = Math.PI * 2 * (i / sides);
|
||||
poly.push(Math.cos(rad + offset) * radius, Math.sin(rad + offset) * radius);
|
||||
}
|
||||
return poly;
|
||||
}
|
||||
// Bevel the corners of polygon
|
||||
function polyBevel(poly: number[], cornerScale = 0.2, cornerDiv = 3) {
|
||||
const polyOut: number[] = [];
|
||||
const len = poly.length / 2;
|
||||
const a = new Vec2(); // 3 Points that forms a Polygon Corner
|
||||
const b = new Vec2();
|
||||
const c = new Vec2();
|
||||
|
||||
const va = new Vec2(); // Min/Max Points of the corner to bevel
|
||||
const vb = new Vec2();
|
||||
|
||||
const norma = new Vec2(); // Inward Normals of the Corner Edges
|
||||
const normb = new Vec2();
|
||||
const pivot = new Vec2(); // Pivot point to create curved points
|
||||
// eslint-disable-next-line
|
||||
const v = new Vec2() as any;
|
||||
let ii, i, j, k, radius;
|
||||
for (j = 0; j < len; j++) {
|
||||
i = mod(j - 1, len); // Previous Point
|
||||
k = mod(j + 1, len); // Next Point
|
||||
|
||||
a.fromBuf(poly, i * 2); // Get the Point Positions out of flat buffer
|
||||
b.fromBuf(poly, j * 2);
|
||||
c.fromBuf(poly, k * 2);
|
||||
|
||||
va.fromLerp(a, b, 1.0 - cornerScale); // Get the two points to start and end curved corner
|
||||
vb.fromLerp(b, c, cornerScale);
|
||||
norma.fromSub(b, a).perpCCW().norm(); // Compute Inward normal of the two edges
|
||||
normb.fromSub(c, b).perpCCW().norm();
|
||||
|
||||
raysIntersection(va, norma, vb, normb, pivot); // Point where the 2 normals converge.
|
||||
|
||||
radius = Vec2.len(va, pivot); // Get the Radius for the curved corner
|
||||
va.pushTo(polyOut);
|
||||
|
||||
for (ii = 1; ii < cornerDiv; ii++) {
|
||||
// Fill in the remaining points
|
||||
v.fromLerp(va, vb, ii / cornerDiv) // Lerp between Start + end Points
|
||||
.sub(pivot) // Localize it
|
||||
.norm() // Normalize it
|
||||
.scale(radius) // Scale it to the radius
|
||||
.add(pivot) // Move it back to world space
|
||||
.pushTo(polyOut);
|
||||
}
|
||||
vb.pushTo(polyOut);
|
||||
}
|
||||
return polyOut;
|
||||
}
|
||||
|
||||
function mod(a: number, b: number): number {
|
||||
const v = a % b;
|
||||
return v < 0 ? b + v : v;
|
||||
}
|
||||
// Turn 2D Polygon Points into 3D Vertices
|
||||
function toVec3(
|
||||
geo: { normals: number[]; vertices: number[] },
|
||||
poly: number[],
|
||||
offset?: Vec3 | number[]
|
||||
) {
|
||||
const v = new Vec3();
|
||||
// eslint-disable-next-line
|
||||
let i: any;
|
||||
offset = offset || [0, 0, 0];
|
||||
for (i of Vec2.bufIter(poly)) {
|
||||
v.fromVec2(i, true)
|
||||
.add(offset)
|
||||
.pushTo(geo.vertices)
|
||||
.sub(offset)
|
||||
.norm()
|
||||
.pushTo(geo.normals);
|
||||
}
|
||||
}
|
||||
// Create a Beveled cap for the extruded walls
|
||||
function polyCapBevel(
|
||||
geo: { normals: number[]; vertices: number[] },
|
||||
poly: number[],
|
||||
cornerDiv: number,
|
||||
capSize: number,
|
||||
offset?: Vec3 | number[]
|
||||
) {
|
||||
// eslint-disable-next-line
|
||||
const v: any = new Vec2();
|
||||
const lerp = [];
|
||||
let pivot, top, pnt, i, vlen, tlen;
|
||||
|
||||
offset = offset || [0, 0, 0];
|
||||
for (i = 0; i < poly.length; i += 2) {
|
||||
v.fromBuf(poly, i);
|
||||
|
||||
vlen = v.len();
|
||||
tlen = vlen - capSize;
|
||||
pnt = new Vec3().fromVec2(v, true);
|
||||
pivot = Vec3.scale(pnt, tlen / vlen);
|
||||
top = Vec3.add(pivot, [0, capSize, 0]);
|
||||
|
||||
lerp.push({ pivot, top, pnt });
|
||||
}
|
||||
let t, itm;
|
||||
pnt = new Vec3();
|
||||
for (i = 1; i <= cornerDiv; i++) {
|
||||
t = i / cornerDiv;
|
||||
for (itm of lerp) {
|
||||
pnt
|
||||
.fromLerp(itm.pnt, itm.top, t)
|
||||
.sub(itm.pivot)
|
||||
.norm()
|
||||
.pushTo(geo.normals)
|
||||
.scale(capSize)
|
||||
.add(itm.pivot)
|
||||
.add(offset)
|
||||
.pushTo(geo.vertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/2931573/determining-if-two-rays-intersect
|
||||
function raysIntersection(as: Vec2, ad: Vec2, bs: Vec2, bd: Vec2, out: Vec2) {
|
||||
const dx = bs[0] - as[0];
|
||||
const dy = bs[1] - as[1];
|
||||
const det = bd[0] * ad[1] - bd[1] * ad[0];
|
||||
|
||||
if (det != 0) {
|
||||
// near parallel line will yield noisy results
|
||||
const u = (dy * bd[0] - dx * bd[1]) / det;
|
||||
const v = (dy * ad[0] - dx * ad[1]) / det;
|
||||
|
||||
if (u >= 0 && v >= 0) {
|
||||
out[0] = as[0] + ad[0] * u;
|
||||
out[1] = as[1] + ad[1] * u;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/** Generate Indices of both a Looped or Unlooped Grid, Backslash Pattern, Loops on Columns */
|
||||
function gridIndicesCol(
|
||||
out: number[],
|
||||
row_size: number,
|
||||
row_cnt: number,
|
||||
start_idx = 0,
|
||||
do_loop = false,
|
||||
rev_quad = false
|
||||
) {
|
||||
const row_stop = row_cnt - 1,
|
||||
col_stop = do_loop ? row_size : row_size - 1;
|
||||
let row_a, row_b, r, rr, rrr, a, b, c, d;
|
||||
for (r = 0; r < row_stop; r++) {
|
||||
// Figure out the starting Index for the Two Rows
|
||||
// 2nd row might loop back to starting row when Looping.
|
||||
row_a = start_idx + row_size * r;
|
||||
row_b = start_idx + row_size * (r + 1);
|
||||
for (rr = 0; rr < col_stop; rr++) {
|
||||
// Defined the Vertex Index of a Quad
|
||||
rrr = (rr + 1) % row_size;
|
||||
a = row_a + rr;
|
||||
b = row_a + rrr;
|
||||
d = row_b + rr;
|
||||
c = row_b + rrr;
|
||||
if (!rev_quad) out.push(a, b, c, c, d, a);
|
||||
// Counter ClockWise
|
||||
else out.push(a, d, c, c, b, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
function fanIndices(
|
||||
out: number[],
|
||||
midIdx: number,
|
||||
edgeStart: number,
|
||||
edgeEnd: number,
|
||||
rev_quad = false
|
||||
) {
|
||||
const len = edgeEnd - edgeStart + 1;
|
||||
let i, ii;
|
||||
for (i = 0; i < len; i++) {
|
||||
ii = (i + 1) % len; // Next Point on the edge
|
||||
if (!rev_quad) out.push(midIdx, edgeStart + i, edgeStart + ii);
|
||||
// Counter ClockWise
|
||||
else out.push(midIdx, edgeStart + ii, edgeStart + i);
|
||||
}
|
||||
}
|
||||
export default HexagonPillar;
|
23
src/views/service/Endpoints.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="enpoints">This is a enpoint page</div>
|
||||
</template>
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="scss" scoped>
|
||||
div {
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
24
src/views/service/Metrics.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div>This is the Metrics page</div>
|
||||
</template>
|
||||
<script lang="ts" setup></script>
|
||||
<style lang="scss" scoped>
|
||||
div {
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
101
src/views/service/Panel.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="service-detail">
|
||||
<div class="title">
|
||||
<span>{{ state.serviceID }}</span>
|
||||
<span>Types</span>
|
||||
<span>Technologies</span>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<router-link
|
||||
class="tab cp"
|
||||
v-for="tab in tabs"
|
||||
:key="tab"
|
||||
@click="handleClick(tab)"
|
||||
:class="{ active: tab === activeName }"
|
||||
:to="`${state.path}/${state.serviceID}/${tab}`"
|
||||
>
|
||||
{{ t(tab) }}
|
||||
</router-link>
|
||||
</div>
|
||||
<Endpoints v-if="state.type === tabs[2]" />
|
||||
<Metrics v-else-if="state.type === tabs[0]" />
|
||||
<Topology
|
||||
v-else-if="state.type === tabs[1]"
|
||||
msg="This is the Topology page"
|
||||
/>
|
||||
<Traces v-else-if="state.type === tabs[3]" msg="This is the Trace page" />
|
||||
<Profiles v-else msg="This is the Profiles page" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRoute } from "vue-router";
|
||||
import Metrics from "./Metrics.vue";
|
||||
import Endpoints from "./Endpoints.vue";
|
||||
import Topology from "./Topology.vue";
|
||||
import Traces from "./Traces.vue";
|
||||
import Profiles from "./Profiles.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const tabs = ["metrics", "topologies", "endpoints", "traces", "profiles"];
|
||||
const activeName = ref<string>(tabs[0]);
|
||||
const state = reactive({
|
||||
serviceID: route.params.id,
|
||||
type: route.params.type,
|
||||
path: route.meta.headPath,
|
||||
});
|
||||
function handleClick(tab: string) {
|
||||
activeName.value = tab;
|
||||
state.type = tab;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.service-detail {
|
||||
text-align: left;
|
||||
}
|
||||
.tabs {
|
||||
padding: 15px 15px 0 15px;
|
||||
border-bottom: 1px solid var(--el-border-color-light);
|
||||
}
|
||||
.tab {
|
||||
display: inline-block;
|
||||
margin-right: 30px;
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
height: 30px;
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
&.active {
|
||||
color: var(--el-color-primary);
|
||||
border-bottom: 1px solid var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
.title {
|
||||
padding: 5px 0 5px 15px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
border-bottom: 1px solid #dfe4e8;
|
||||
background-color: #c4c8e133;
|
||||
span {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
31
src/views/service/Profiles.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div>{{ msg }}</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
defineProps({
|
||||
msg: { type: String },
|
||||
});
|
||||
// props.msg
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div {
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
30
src/views/service/Topology.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div>Topology</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
defineProps({
|
||||
msg: { type: String },
|
||||
});
|
||||
// props.msg
|
||||
</script>
|
||||
<style scoped>
|
||||
div {
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
31
src/views/service/Traces.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div>Traces</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from "vue";
|
||||
defineProps({
|
||||
msg: { type: String },
|
||||
});
|
||||
// props.msg
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div {
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
41
src/views/service/data.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const TabsConfig: { [key: string]: any } = {
|
||||
GeneralService: [
|
||||
{ name: "metrics", path: "/generalService/metrics" },
|
||||
{ name: "traces", path: "/generalService/traces" },
|
||||
{ name: "profiles", path: "/generalService/profiles" },
|
||||
{ name: "services", path: "/generalService" },
|
||||
],
|
||||
ServiceMesh: [
|
||||
{ name: "services", path: "/serviceMesh" },
|
||||
{ name: "metrics", path: "/serviceMesh/metrics" },
|
||||
{ name: "traces", path: "/serviceMesh/traces" },
|
||||
{ name: "profiles", path: "/serviceMesh/profiles" },
|
||||
],
|
||||
};
|
||||
export const PagesConfig = [
|
||||
{ label: "generalService", name: "GeneralService" },
|
||||
{ label: "serviceMesh", name: "ServiceMesh" },
|
||||
{ label: "virtualMachine", name: "VirtualMachine" },
|
||||
{ label: "dashboardHome", name: "DashboardHome" },
|
||||
{ label: "dashboardList", name: "DashboardList" },
|
||||
{ label: "logs", name: "Logs" },
|
||||
{ label: "settings", name: "Settings" },
|
||||
{ label: "events", name: "Events" },
|
||||
{ label: "alerts", name: "Alerts" },
|
||||
];
|