Commit 265f2a0b authored by 何小勇's avatar 何小勇

init

parents
platform:
runner: 10.11.92.34
kind: pipeline
name: dev
trigger:
branch:
- dev
clone:
disable: true
volumes:
- name: docker-sock
host:
path: /var/run/docker.sock
##-------------------------------流水线⬇-------------------------------##
steps: # 定义流水线执行步骤,这些步骤将顺序执行
- name: fetch
image: registry.cn-qingdao.aliyuncs.com/wod/devops-git:1.0
network_mode: host
- name: s3-cache
image: registry.cn-qingdao.aliyuncs.com/wod/devops-s3-cache:1.0
network_mode: host
settings:
restore: true
mount:
- ./node_modules
endpoint: http://cache.wodcloud.com
access_key:
from_secret: ACCESS_KEY_MINIO
secret_key:
from_secret: SECRET_KEY_MINIO
- name: build # 项目打包
image: registry.cn-qingdao.aliyuncs.com/wod/devops-node:16.16.0-slim
# 将宿主机中文件夹挂载到容器中,宿主机文件夹中的文件会被容器访问并修改,起到使用缓存的作用,避免每次运行都要重现下载依赖,提高运行速度
commands:
# - yarn
- export NODE_ENV=production
- yarn build
# - name: s3-cache-build
# image: registry.cn-qingdao.aliyuncs.com/wod/devops-s3-cache:1.0
# network_mode: host
# settings:
# rebuild: true
# hash: package.json
# mount:
# - node_modules
# endpoint: http://cache.wodcloud.com
# access_key:
# from_secret: ACCESS_KEY_MINIO
# secret_key:
# from_secret: SECRET_KEY_MINIO
- name: docker
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker:1.0
# 将宿主机的 docker和配置挂载到运行的 docker 容器中,那么在容器中运行 docker 命令时,等同于在宿主机中运行该docker命令
volumes:
- name: docker-sock
path: /var/run/docker.sock # 将下载依赖的目录挂载出来,防止重复下载
settings: # 当前设置
base: registry.cn-qingdao.aliyuncs.com/wod/nginx:1.19.5 # 基础镜像,根据项目需求进行使用,如果第三方登录改成ui-base
dockerfile: .beagle/dockerfile
repo: wod/apaas-system-ui # 生成镜像的 分组/名称
version: "5.0.1" # 版本号
channel: alpha # 后缀 example: alpha test fix-alpha fix等
args: "TARGETOS=linux,TARGETARCH=amd64" # 不同架构的构建参数
registry: registry.cn-qingdao.aliyuncs.com # 私有仓库地址
registry_user: # 用户
from_secret: REGISTRY_USER_ALIYUN
registry_password: # 密码
from_secret: REGISTRY_PASSWORD_ALIYUN
- name: deploy-cloud
image: registry.cn-qingdao.aliyuncs.com/wod/devops-kubernetes:1.0
settings:
namespace: apaas-v5
deployment: apaas-system-ui
container: apaas-system-ui
image: registry.cn-qingdao.aliyuncs.com/wod/apaas-ui:5.0.1-alpha
environment:
KUBERNETES_SERVER:
from_secret: KUBERNETES_SERVER
KUBERNETES_TOKEN:
from_secret: KUBERNETES_TOKEN
- name: docker-arm64
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker:1.0
volumes:
- name: docker-sock
path: /var/run/docker.sock
settings:
base: registry.cn-qingdao.aliyuncs.com/wod/nginx:1.19.5-arm64
dockerfile: .beagle/dockerfile
repo: wod/apaas-system-ui
version: "5.0.1"
channel: alpha-arm64
args: "TARGETOS=linux,TARGETARCH=arm64"
registry: registry.cn-qingdao.aliyuncs.com
registry_user:
from_secret: REGISTRY_USER_ALIYUN
registry_password:
from_secret: REGISTRY_PASSWORD_ALIYUN
---
clone:
disable: true
trigger:
branch:
- master
volumes:
- name: docker-sock
host:
path: /var/run/docker.sock
kind: pipeline
name: master
steps:
- name: harbor
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker-tag:1.0
volumes:
- name: docker-sock
path: /var/run/docker.sock
pull: always
environment:
http_proxy: http://10.11.92.33:1282
https_proxy: http://10.11.92.33:1282
REGISTRY_USER:
from_secret: REGISTRY_USER_ALIYUN
REGISTRY_PASSWORD:
from_secret: REGISTRY_PASSWORD_ALIYUN
settings:
source: registry.cn-qingdao.aliyuncs.com/wod/apaas-system-ui:5.0.1-alpha
target: registry.cn-qingdao.aliyuncs.com/wod/apaas-system-ui:5.0.1
registry: registry.cn-qingdao.aliyuncs.com
- name: harbor-arm64
image: registry.cn-qingdao.aliyuncs.com/wod/devops-docker-tag:1.0
volumes:
- name: docker-sock
path: /var/run/docker.sock
pull: always
environment:
http_proxy: http://10.11.92.33:1282
https_proxy: http://10.11.92.33:1282
REGISTRY_USER:
from_secret: REGISTRY_USER_ALIYUN
REGISTRY_PASSWORD:
from_secret: REGISTRY_PASSWORD_ALIYUN
settings:
source: registry.cn-qingdao.aliyuncs.com/wod/apaas-system-ui:5.0.1-alpha-arm64
target: registry.cn-qingdao.aliyuncs.com/wod/apaas-system-ui:5.0.1-arm64
registry: registry.cn-qingdao.aliyuncs.com
##--------------对于需要保密的信息隐藏,减少账户信息的泄密⬇-----------------##
---
kind: secret
name: REGISTRY_USER
get:
name: REGISTRY_USER
path: devops-secrets
---
kind: secret
name: REGISTRY_PASSWORD
get:
name: REGISTRY_PASSWORD
path: devops-secrets
---
kind: secret
name: KUBERNETES_SERVER
get:
name: KUBERNETES_SERVER
path: devops-secrets
---
kind: secret
name: KUBERNETES_TOKEN
get:
name: KUBERNETES_TOKEN
path: devops-secrets
---
kind: secret
name: ACCESS_KEY_MINIO
get:
name: ACCESS_KEY
path: devops-secrets
---
kind: secret
name: SECRET_KEY_MINIO
get:
name: SECRET_KEY
path: devops-secrets
---
kind: secret
name: REGISTRY_USER_ALIYUN
get:
name: USERNAME
path: devops-registry-aliyun
---
kind: secret
name: REGISTRY_PASSWORD_ALIYUN
get:
name: PASSWORD
path: devops-registry-aliyun
\ No newline at end of file
ARG BASE
FROM $BASE
ARG AUTHOR
ARG VERSION
LABEL maintainer=${AUTHOR} version=${VERSION}
ADD ./dist /usr/share/nginx/html
ADD ./.beagle/nginx.conf /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 8080;
listen [::]:8080;
server_name localhost;
absolute_redirect off; #取消绝对路径的重定向
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location /apaas/ui {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /apaas/ui/index.html;
}
}
# 开启gzip
gzip off;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 6;
# 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。
# 由于jpg,jpeg,png本来就是压缩格式,再行压缩只会消耗cpu资源,帮助并不大
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/gif;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
#压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_http_version 1.0;
# 禁用IE 6 gzip
gzip_disable "MSIE [1-6]\.";
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
\ No newline at end of file
node_modules
.DS_Store
.vscode
dist
dist-ssr
*.local
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>apaas5</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
<style>
html, body{
width: 100%;
height: 100%;
background-color: #eef0f5;
margin: 0;
}
div,p,span{
box-sizing: border-box;
}
</style>
This diff is collapsed.
{
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.0.6",
"@wangeditor/editor": "^5.1.14",
"@wangeditor/editor-for-vue": "^5.1.12",
"ace-builds": "^1.9.6",
"axios": "^0.21.1",
"clipboard": "^2.0.11",
"echarts": "^5.3.3",
"element-plus": "^2.2.9",
"html2canvas": "^1.4.1",
"sass": "^1.35.1",
"uuid": "^8.3.2",
"vue": "^3.2.31",
"vue-i18n": "^9.1.7",
"vue-router": "^4.0.10",
"vue3-ace-editor": "^2.2.2",
"vuex": "^4.0.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^3.0.0",
"@vue/compiler-sfc": "^3.2.31",
"vite": "^3.0.0"
}
}
<template>
<div id="app">
<el-config-provider>
<bg-menu :path="nowParent.path" v-if="menuShow"></bg-menu>
<div class="container" :class="menuShow ? '' : 'full_screen'" v-if="pageShow">
<bg-nav :highlightParentRule="highlightParentRule" :title="nowParent.menuName" width="208px" :list="nowParent.children" v-show="navShow" class="con-nav" />
<div class="bg-main view">
<router-view />
</div>
</div>
<div class="container" v-else-if="$route.path=='/login'">
<div class="bg-main view">
<login></login>
</div>
</div>
<div class="container" v-else-if="$route.path=='/404'">
<div class="bg-main view">
<page404></page404>
</div>
</div>
</el-config-provider>
</div>
</template>
<script>
import bgMenu from '@/components/bg-menu.vue'
import login from '@/page/login/index.vue'
import page404 from '@/page/404.vue'
export default {
components:{
bgMenu,
login,
page404,
},
computed:{
msgBoxFlag(){
return this.$store.state.msgBoxFlag
},
userInfo() {
return this.$store.state.userInfo || {};
},
navMenu(){
return this.$store.state.menu
},
menuObj(){
return this.$store.state.menuObj
},
navShow(){
return false||!['/','/404','/login'].includes(this.$route.path)
},
pageShow(){
return false||!['/404','/login'].includes(this.$route.path)
},
rowPath(){
if(this.pageShow&&this.$store.state.userInfo){
return this.menuObj[this.$route.path].rowPath
}else{
return ''
}
},
nowParent(){
if(this.pageShow&&this.$store.state.userInfo){
// return this.navMenu[this.rowPath.slice(1,4)]
// return this.pathToData(this.navMenu,this.rowPath)
return this.navMenu[1]
}else{
return ''
}
},
menuShow() {
return false||!["/ui-example"].includes(this.$route.path)
}
},
watch:{
msgBoxFlag(n,o){
this.readFlag = !this.readFlag
}
},
data(){
return{
readFlag:false,
menuIndex:'',
}
},
created(){
},
methods:{
pathToData(data,path){
let arr = path.split('.')
let temp = null
let tempName = ''
let tempPath = ''
arr.forEach((e,idx) => {
if(idx==1){
temp = data[e]
tempName = data[e].menuName
tempPath = data[e].path
data = data[e]
}
if(idx==2){
if(data.children&&data.children.length){
temp = data.children[e]
data = data.children[e]
}
}
});
return {
menuName:tempName,
path:tempPath,
children:[temp]
}
},
highlightParentRule(pathArr){
return pathArr.includes(this.$route.path)
},
ada(){
console.log(12312);
}
}
}
</script>
<style>
#app{
height: 100%;
}
.container{
width: 100%;
height: calc(100% - 56px);
overflow: hidden;
}
.full_screen {
height: 100%;
}
.full_screen .bg-main {
overflow-x: hidden;
}
.con-nav{
float: left;
}
.view{
height: 100%;
overflow-y: auto;
background-color: #ebedf2;
}
</style>
This diff is collapsed.
@font-face {
font-family: 'Digital-7Mono';
src: url('Digital-7Mono.ttf');
font-weight: normal;
font-style: normal;
}
\ No newline at end of file
.page_container {
width: 100%;
padding: 0 24px;
/* min-height: 100%; */
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
.page_content {
background-color: #fff;
height: calc(100% - 46px - 20px);
box-shadow: 0px 1px 4px 0px
rgba(0, 7, 101, 0.15);
border-radius: 6px;
}
\ No newline at end of file
export const lang = {
}
\ No newline at end of file
:root {
--font-color: #404a62;
/* --el-color-primary-light-9: #f7f7f9; */
--el-color-white: #ffffff;
--el-color-black: #1a1a1a;
--el-color-primary: #2b4695;
--el-color-primary-light-3: #6b7eb5;
--el-color-primary-light-5: #95a3ca;
--el-color-primary-light-7: #c0c8df;
--el-color-primary-light-8: #d5daea;
--el-color-primary-light-9: #eaedf5;
--el-color-primary-dark-2: #223877;
--el-color-success: #429e8a;
--el-color-success-light-3: #7bbbad;
--el-color-success-light-5: #a1cfc5;
--el-color-success-light-7: #c7e2dc;
--el-color-success-light-8: #d9ece8;
--el-color-success-light-9: #ecf5f4;
--el-color-success-dark-2: #357e6e;
--el-color-warning: #e56600;
--el-color-warning-light-3: #ed944d;
--el-color-warning-light-5: #f2b380;
--el-color-warning-light-7: #f7d1b3;
--el-color-warning-light-8: #fae0cc;
--el-color-warning-light-9: #fcf0e6;
--el-color-warning-dark-2: #b75200;
--el-color-danger: #d75138;
--el-color-danger-light-3: #e38674;
--el-color-danger-light-5: #eba89c;
--el-color-danger-light-7: #f3cbc4;
--el-color-danger-light-8: #f7dcd7;
--el-color-danger-light-9: #fbeeeb;
--el-color-danger-dark-2: #ac412d;
--el-color-error: #d75138;
--el-color-error-light-3: #e38674;
--el-color-error-light-5: #eba89c;
--el-color-error-light-7: #f3cbc4;
--el-color-error-light-8: #f7dcd7;
--el-color-error-light-9: #fbeeeb;
--el-color-error-dark-2: #ac412d;
--el-color-info: #404a62;
--el-color-info-light-3: #7a8191;
--el-color-info-light-5: #a0a5b1;
--el-color-info-light-7: #c6c9d0;
--el-color-info-light-8: #d9dbe0;
--el-color-info-light-9: #ecedf0;
--el-color-info-dark-2: #333b4e;
--el-bg-color: #ffffff;
--el-bg-color-page: #f2f3f5;
--el-bg-color-overlay: #ffffff;
--el-text-color-primary: #202531;
--el-text-color-regular: #404a62;
--el-text-color-secondary: #909bb6;
--el-text-color-placeholder: #a9b1c7;
--el-text-color-disabled: #a9b1c7;
--el-border-color: #dadee7;
--el-border-color-light: #e3e5eb;
--el-border-color-lighter: #e6e9ef;
--el-border-color-extra-light: #edf0f5;
--el-border-color-dark: #d1d5de;
--el-border-color-darker: #cbced7;
--el-fill-color: #f0f2f5;
--el-fill-color-light: #f2f3f7;
--el-fill-color-lighter: #f7f7f9;
--el-fill-color-extra-light: #fafcff;
--el-fill-color-dark: #ebedf0;
--el-fill-color-darker: #e6e8eb;
--el-fill-color-blank: #ffffff;
}
.text-hide1{
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
.log_content_nor::-webkit-scrollbar {
width: 0px; /*对垂直流动条有效*/
height: 0px; /*对水平流动条有效*/
}
\ No newline at end of file
<template>
<div class="bg-btns">
<ul>
<li
v-for="btn in options"
:class="{
'is-active': modelValue === btn.value,
}"
:key="btn.value"
@click="selectBtn(btn)"
>
{{ btn.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "BgBtns",
props: {
modelValue: {
type: [String, Number],
default: "",
},
options: {
type: Array,
default: () => [],
},
},
emits: ["update:modelValue"],
methods: {
selectBtn({ value }) {
this.$emit("update:modelValue", value);
},
},
};
</script>
<template>
<div class="bg-card">
<h3 class="card-title text-clip">
<span class="title-icon" v-if="icon">
<bg-icon :icon="icon" />
</span>
<span class="text-text">{{ title }}</span>
</h3>
<div class="card-content" ref="content">
<slot />
</div>
</div>
</template>
<script>
export default {
name: "BgCard",
props: {
title: {
type: String,
default: "",
},
icon: {
type: String,
default: "",
},
},
};
</script>
<template>
<VAceEditor
v-model:value="states.content"
class="vue-ace-editor"
:class="{'vue-ace-editor-disable':props.disabled}"
@input="codeChange"
:lang="props.lang"
:theme="props.theme"
:options="{
useWorker: true,
readOnly: props.disabled,
wrap: true
}"
/>
</template>
<script setup>
import { reactive, toRefs, watch,onMounted } from "vue";
import { VAceEditor } from "vue3-ace-editor";
import ace from 'ace-builds';
import modeJsonUrl from 'ace-builds/src-noconflict/mode-json?url';
import modeJavascriptUrl from 'ace-builds/src-noconflict/mode-javascript?url';
import modeHtmlUrl from 'ace-builds/src-noconflict/mode-html?url';
import themeGithubUrl from 'ace-builds/src-noconflict/theme-github?url';
import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url';
import themeMonokaiUrl from 'ace-builds/src-noconflict/theme-monokai?url';
import workerBaseUrl from 'ace-builds/src-noconflict/worker-base?url';
import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url';
import workerJavascriptUrl from 'ace-builds/src-noconflict/worker-javascript?url';
import workerHtmlUrl from 'ace-builds/src-noconflict/worker-html?url';
ace.config.setModuleUrl('ace/mode/json', modeJsonUrl);
ace.config.setModuleUrl('ace/mode/javascript', modeJavascriptUrl);
ace.config.setModuleUrl('ace/mode/html', modeHtmlUrl);
ace.config.setModuleUrl('ace/theme/github', themeGithubUrl);
ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl);
ace.config.setModuleUrl('ace/theme/monokai', themeMonokaiUrl);
ace.config.setModuleUrl('ace/mode/base', workerBaseUrl);
ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl);
ace.config.setModuleUrl('ace/mode/javascript_worker', workerJavascriptUrl);
ace.config.setModuleUrl('ace/mode/html_worker', workerHtmlUrl);
const props = defineProps(
{
modelValue: {
type:String,
default:"",
},
disabled:{
type:Boolean,
default:false
},
// lang:{
// type:String,
// default:"json"
// },
// theme:{
// type:String,
// default:"themeChromeUrl"
// },
width:{
type:String,
default:"100%"
},
}
)
const emit = defineEmits(['update:modelValue'])
watch(
props.modelValue,
(n,o) => {
states.content = n
}
)
const states = reactive({
lang: "json",
theme: "github",
content: "",
});
watch(
states.content,
(n,o) => {
emit("update:modelValue", n);
}
)
const codeChange = (val,val1,val2)=>{
emit("update:modelValue", val1.renderer.content.innerText);
}
onMounted(() => {
let obj = "";
// console.log(typeof JSON.parse(this.datas));
try {
if (typeof JSON.parse(props.modelValue) == "object") {
obj = JSON.stringify(JSON.parse(props.modelValue), null, "\t");
}
} catch (e) {
obj = props.modelValue;
}
states.content = obj
})
const {content} = toRefs(states)
</script>
<style scoped>
.vue-ace-editor {
flex: 1;
margin-top: 15px;
font-size: 16px;
border: 1px solid #dadee7;
width: 100%;
height: 100%;
border-radius: 4px;
overflow: hidden;
}
.vue-ace-editor :deep() .ace_scrollbar-v{
width: 0px!important;
}
.vue-ace-editor :deep() .ace_gutter{
font-size: 14px;
color: #ffffff;
background-color: #262626;
}
.vue-ace-editor :deep() .ace_gutter-cell{
line-height: 22px;
background-color: #262626;
}
.vue-ace-editor :deep() .ace_print-margin{
width: 0;
}
.vue-ace-editor :deep() .ace_scroller{
background-color: #1a1a1a;
color: #fff;
caret-color:#fff;
}
/* 光标颜色 */
.vue-ace-editor :deep() .ace_cursor{
color: #fff;
}
.vue-ace-editor-disable :deep() .ace_scrollbar-v{
width: 6px!important;
}
.vue-ace-editor-disable :deep() .ace_gutter{
background-color: #202531;
}
.vue-ace-editor-disable :deep() .ace_gutter-cell{
background-color: #202531;
}
.vue-ace-editor-disable :deep() .ace_scroller{
background-color: #fff;
color: #202531;
}
/* 光标颜色 */
.vue-ace-editor-disable :deep() .ace_cursor{
color: #000;
}
</style>
<template>
<div class="detail_box">
<div class="detail_text text_clip" :style="index==data.length-1?last_width:unit_width" v-for="(item,index) in data" :key="'data'+index">
<span>{{item.title}}</span>
<!-- 拓展功能 -->
<template v-if="item.slot">
<span>
<slot v-bind:item="item" :name="item.slot"></slot>
</span>
</template>
<!-- 原有下载功能 -->
<template v-else>
<span v-if="!item.urls" :title="item.info" @click="down_file(item.url)" :style="item.url?{color:'#515fe7',cursor:'pointer'}:''">{{item.info}}</span>
<span v-else :title="item.info">
<span v-for="(it,idx) in item.urls" @click="down_file(it)" style="color:#515fe7;cursor:pointer;" :key="'urls'+idx">{{helper.downloadFileFormatNew(it)}}</span>
</span>
</template>
</div>
<div class="bg" :style="{top:(2*index+1)*42+'px'}" v-for="(item,index) in bg_num" :key="'bg'+index"></div>
</div>
</template>
<script>
import helper from './utils/index.js'
console.log(helper);
export default {
props: {
data:{
type: Array,
default: () => [],
},
layout:{
line_num:4
}
},
components: {
},
data() {
return {
helper,
unit_width:0,
last_width:0,
bg_num:0,
};
},
watch: {
data:{
handler: function(n, o) {
if(this.layout.line_num){
this.unit_width = {width:100/this.layout.line_num +'%'}
}
if(this.layout.line_num&&n.length%this.layout.line_num!==0){//计算最后一个格子的宽度
this.last_width = {width:(this.layout.line_num-(n.length%this.layout.line_num)+1)/this.layout.line_num*100+'%'}
}else{
this.last_width = {width:100/this.layout.line_num +'%'}
}
if(n.length<this.layout.line_num){
return
}else{
this.bg_num = Math.floor((Math.ceil(n.length/this.layout.line_num))/2)
}
},
immediate: true
}
},
computed: {
},
created() {
},
mounted() {
},
methods: {
down_file(url){
if(url){
console.log(url);
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件
}
}
},
};
</script>
<style scoped>
.detail_box{
width: 100%;
border-bottom: 1px solid #e3e5ef;
border-right: 1px solid #e3e5ef;
overflow: hidden;
position: relative;
}
.detail_box .detail_text{
width: 25%;
height: 42px;
line-height: 42px;
padding: 0 15px;
border-left: 1px solid #e3e5ef;
border-top: 1px solid #e3e5ef;
float: left;
position: relative;
z-index: 1;
}
.detail_box .detail_text span:nth-of-type(1){
color: #616f94;
}
.detail_box .detail_text span:nth-of-type(2){
color: #404a62;
}
.bg{
background-color:#f7f8f9;
width: 100%;
height: 42px;
position: absolute;
}
</style>
<template>
<div class="out-detail">
<div class="row-box" v-for="(item,index) in list" :style="{width:item.width}" :key="'row-box'+index">
<p class="detail-module" v-if="!item.slot">
<span :style="{width:itemWidth}">{{item.label}}</span>
<span class="text_clip" :title="item.value" v-if="!item.childSlot">{{item.value}}</span>
<span v-else>
<slot :name="item.childSlot" :data="item"></slot>
</span>
</p>
<template v-else>
<slot :name="item.slot" :data="item"></slot>
</template>
</div>
</div>
</template>
<script>
export default {
props: {
list:{
type:Array,
default:()=>[]
},
itemWidth:{
type:String,
default:''
}
},
components: {
},
data() {
return {
};
},
watch: {
},
computed: {
},
created() {
},
mounted() {
},
methods: {
},
};
</script>
<style scoped>
.out-detail{
width: 100%;
overflow: hidden;
display: flex;
flex-wrap: wrap;
border-right: solid 1px #dadee7;
border-bottom: solid 1px #dadee7;
}
.row-box{
width: 50%;
flex-grow:1;
text-align: left;
line-height: 48px;
min-height: 48px;
border-left: solid 1px #dadee7;
border-top: solid 1px #dadee7;
font-size: 14px;
color: #404a62;
}
.row-box .detail-module{
height: 100%;
display: flex;
}
.row-box .detail-module span{
height: 100%;
display: inline-block;
padding-left: 15px;
box-sizing: border-box;
}
.row-box .detail-module span:nth-of-type(1){
background-color: #f7f7f9;
min-width: 114px;
border-right: solid 1px #dadee7;
}
.row-box .detail-module span:nth-of-type(2){
flex-grow:1;
}
</style>
<template>
<div class="bg-detail bg-form">
<!-- 固定导航 -->
<div class="bg-tabs-nav--fixed" v-show="showFixedBars">
<ul v-if="calcTabs().length">
<li
v-for="(item, index) in calcTabs()"
:key="'tab_' + index"
:class="{
current: activeName === item.name,
}"
@click="changeActiveName(item, index)"
>
{{ item.label }}
</li>
<li>
<!-- empty -->
</li>
</ul>
</div>
<!-- 面包屑 -->
<div class="bg-breadcrumb">
<slot name="breadcrumb" />
</div>
<!-- 基本信息 -->
<div class="bg-detail-info" v-if="$slots.info">
<slot name="info" />
</div>
<!-- 兼容意外模块 -->
<div v-if="$slots.other">
<slot name="other" />
</div>
<!-- 详情 -->
<div class="bg-tabs bg-detail-tabs">
<div class="bg-tabs-nav" v-if="calcTabs().length">
<ul>
<li
v-for="(item, index) in calcTabs()"
:key="'tab_' + index"
:class="{
current: activeName === item.name,
}"
@click="changeActiveName(item, index)"
>
{{ item.label }}
</li>
<li>
<!-- empty -->
</li>
</ul>
</div>
<div class="bg-tabs-content">
<slot />
</div>
</div>
</div>
</template>
<script>
export default {
name: "BgDetail",
provide() {
return {
getActiveName: () => {
return this.activeName;
},
getIsTabs: () => {
return false;
},
};
},
data() {
return {
activeName: "",
showFixedBars: false,
scrollCallback: null,
};
},
methods: {
calcTabs() {
let tabSlots = [];
if (this.$slots.default) {
tabSlots = this.$slots.default
.filter(
(vnode) =>
vnode.tag &&
vnode.componentOptions &&
vnode.componentOptions.Ctor.options.name === "BgTab"
)
.map((vnode) => vnode.componentOptions.propsData);
}
return tabSlots;
},
changeActiveName({ name }, index) {
let targetEl = this.$el.querySelectorAll(`.bg-tab`)[index];
let targetCtx = document.querySelector(`.bg-main`);
targetCtx.scrollTop = targetEl && targetEl.offsetTop - 165;
this.activeName = name;
this.scrollCallback = () => {
this.activeName = name;
};
},
scrollAction() {
let targetCtx = document.querySelector(`.bg-main`);
let ctxScrollTop = targetCtx.scrollTop || 0;
let targetEls = this.$el.querySelectorAll(`.bg-tab`);
let tabs = this.calcTabs();
for (let i = 0; i < targetEls.length; i++) {
let targetEl = targetEls[i];
if (ctxScrollTop >= targetEl.offsetTop) {
this.activeName = tabs[i].name;
}
}
this.showFixedBars = ctxScrollTop > 222;
this.scrollCallback && this.scrollCallback();
this.scrollCallback = null;
},
},
mounted() {
this.$nextTick(() => {
let tabs = this.calcTabs();
this.activeName = tabs[0] && tabs[0].name;
this.scrollAction();
window.addEventListener("scroll", this.scrollAction, true);
});
},
destroyed() {
window.removeEventListener("scroll", this.scrollAction, true);
},
};
</script>
<template>
<div class="bg-filtrate">
<span class="bg-filtrate-text">{{ name }}</span>
<div class="bg-filtrate-list">
<el-date-picker
v-model="value"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="~"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="change">
</el-date-picker>
</div>
</div>
</template>
<script>
export default {
name: "BgFilterDate",
model: {
prop: "time",
event: "change",
},
props: {
name: {
type: String,
default: "",
},
},
data() {
return {
value: ""
}
},
computed: {
},
methods: {
change(event) {
this.$emit("change", event);
},
},
};
</script>
\ No newline at end of file
<template>
<div class="bg-filter" v-if="options.length > 0">
<span>{{ name }}</span>
<ul>
<li
v-for="(item, index) in fullOptions"
:class="{ current: selection.indexOf(item.value) > -1 }"
:key="'li_' + index"
@click="selectAction(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "BgFilter",
model: {
prop: "value",
event: "change",
},
props: {
isCalc:{
type:Boolean,
default:false,
},
value: {
type: [Number, String],
default: "",
},
name: {
type: String,
default: "",
},
options: {
type: Array,
default: () => [],
},
optionName: {
type: String,
default: "name",
},
optionValue: {
type: String,
default: "value",
},
multiple: {
type: Boolean,
default: false,
},
},
computed: {
fullOptions() {
return [
{
name: "全部",
value: "",
},
...this.options.map((item) => {
return {
name: item[this.optionName],
value: item[this.optionValue] + "",
sub_cate: item.sub_cate ? item.sub_cate : "",
};
}),
];
},
selection() {
let value = this.value + "";
return value.split(",");
},
},
methods: {
selectAction({ value, name, sub_cate }) {
if (value && this.multiple) {
let selection = [...this.selection].filter((v) => v !== "");
let index = selection.findIndex((v) => v === value);
if (index > -1) {
selection.splice(index, 1);
} else {
selection.push(value);
}
this.$emit("change", selection.join(","));
} else {
this.$emit("change", value, name, sub_cate ? sub_cate : "");
}
},
},
};
</script>
<template>
<div class="bg-filtrate">
<span class="bg-filtrate-text">{{ name }}</span>
<ul class="bg-filtrate-list">
<li
v-for="(item, index) in fullOptions"
:class="{ current: selection.indexOf(item.value) > -1 }"
:key="'li_' + index"
@click="selectAction(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "BgFiltrate",
model: {
prop: "value",
event: "change",
},
props: {
value: {
type: [Number, String],
default: "",
},
name: {
type: String,
default: "",
},
options: {
type: Array,
default: () => [],
},
optionName: {
type: String,
default: "name",
},
optionValue: {
type: String,
default: "value",
},
multiple: {
type: Boolean,
default: false,
},
},
computed: {
fullOptions() {
return [
{
name: "全部",
value: "",
},
...this.options.map((item) => {
return {
name: item[this.optionName],
value: item[this.optionValue] + "",
};
}),
];
},
selection() {
let value = this.value + "";
return value.split(",");
},
},
methods: {
selectAction({ value, name }) {
if (value && this.multiple) {
let selection = [...this.selection].filter((v) => v !== "");
let index = selection.findIndex((v) => v === value);
if (index > -1) {
selection.splice(index, 1);
} else {
selection.push(value);
}
this.$emit("change", selection.join(","));
} else {
this.$emit("change", value, name);
}
},
},
};
</script>
\ No newline at end of file
<template>
<svg class="bg-icon" aria-hidden="true">
<use :xlink:href="icon"></use>
</svg>
</template>
<script>
import "https://at.alicdn.com/t/c/font_3622053_guave5wj5s.js";
export default {
props: {
icon: {
type: String,
default: "",
},
},
};
</script>
\ No newline at end of file
<template>
<div class="bg-info">
<ul>
<li
v-for="(item, index) in data"
:key="'li_' + index"
:style="{
width: item.full ? `100%` : `calc(100% / ${col})`,
}"
>
<span :style="{ width: item.nameWidth ? item.nameWidth + 'px' : '50%'}">
{{ item.name }}
</span>
<span :style="{ width: item.nameWidth ? `calc( 100% - ${item.nameWidth + 'px'})` : '50%'}">
<span
style="display: inline-block;width: 100%;white-space: normal;word-break: break-all"
:style="{
width: item.copy ? 'calc(100% - 36px)' : item.download || item.password ? 'calc(100% - 22px)': '100%',
color: item.download ? '#3759be' : '#404a62'
}"
>{{ item.value }}</span>
<a
class="copy-btn"
@click="copyText(item.value, $event)"
v-if="item.copy"
>
复制
</a>
<bg-icon
class="copy-btn"
style="font-size: 14px; color: #a9b1c7;cursor: pointer;"
icon="#bg-ic-download"
v-if="item.download"
@click="download(item.url)"
></bg-icon>
<bg-icon
class="copy-btn"
style="font-size: 14px; color: #a9b1c7;cursor: pointer;"
:icon="show ? '#bg-ic-eye-close' : '#bg-ic-eye'"
v-if="item.password"
@click="changeView(item)"
></bg-icon>
</span>
</li>
</ul>
</div>
</template>
<script>
import Clipboard from "clipboard";
export default {
name: "BgInfo",
props: {
data: {
type: Array,
default: () => [],
},
col: {
type: Number,
default: 2,
},
},
data() {
return {
show: false
}
},
methods: {
clipboardSuccess() {
this.$message({
type: "success",
message: "复制成功",
duration: 1500,
});
},
clipboardError() {
this.$message({
message: "浏览器不支持自动复制",
type: "warning",
});
},
copyText(text, e) {
const clipboard = new Clipboard(e.target, {
text: () => text,
});
clipboard.on("success", () => {
this.clipboardSuccess();
// 释放内存
clipboard.destroy();
});
clipboard.on("error", () => {
// 不支持复制
this.clipboardError();
// 释放内存
clipboard.destroy();
});
// 解决第一次点击不生效的问题,如果没有,第一次点击会不生效
clipboard.onClick(e);
},
download(url) {
const a = document.createElement("a"); // 创建a标签
a.setAttribute("download", ""); // download属性
a.setAttribute("href", url); // href链接
a.click(); // 自执行点击事件
},
changeView(item) {
if (!this.show) {
item.value = item.realValue
}else {
item.value = "***************"
}
this.show = !this.show
}
},
};
</script>
<template>
<div class="inner-container" :style="{height:height[0]+'px',fontSize:height[2]+'px'}">
<div :style="{height:height[1]+'px',lineHeight:height[1]-2+'px'}" :class="{'now-inner':nowIndex==index}" @click="changeInner(index)" v-for="(item,index) in data" :key="'inner'+index">{{item}}</div>
</div>
</template>
<script setup>
import { reactive, ref,onBeforeMount,toRefs } from 'vue'
const props = defineProps({
modelValue:{
type: [String,Number],
default: 0,
},
data: {
type: Array,
default: [],
},
default:{
type: [String,Number],
default: 0
},
height:{
type:Array,
default:[36,32,16]
}
})
const emit = defineEmits(['update:modelValue','change'])
const nowIndex = ref('')
const changeInner = (val)=>{
nowIndex.value = val
emit('update:modelValue',val)
emit('change',val)
}
onBeforeMount(()=>{
nowIndex.value = props.default
})
</script>
<style scoped>
.inner-container{
height: 36px;
background-color: #edeef0;
border-radius: 4px;
padding: 2px;
display: inline-block;
overflow: hidden;
}
.inner-container div{
height: 32px;
line-height: 30px;
border-radius: 4px;
padding:0 15px;
float: left;
color: #404a62;
cursor: pointer;
}
.inner-container .now-inner{
background-color: #2b4695;
color: #ffffff;
}
</style>
This diff is collapsed.
This diff is collapsed.
<template>
<ul class="nav-list" v-if="list&&list.length">
<li v-for="(item, index) in list" v-show="item.show" :key="'nav_' + index">
<template v-if="item.children && item.children.length">
<div
class="nav-item nav-more text-clip"
:class="{ current: isCurrent([item.path]) }"
@click="showMoreAction(index)"
>
<span :style="{ paddingLeft: `${deep*2}em` }">
<!-- <img v-if="item.icon" :src="item.icon" alt=""> -->
<bg-icon v-if="item.icon" :icon="item.icon"></bg-icon>
{{ item.menuName }}
</span>
&ensp;
</div>
<transition name="slideOutUp">
<NavList
:list="item.children"
:deep="deep + 1"
:highlight-parent-rule="highlightParentRule"
v-if="showMore[index] !== false"
/>
</transition>
</template>
<template v-else>
<div
class="nav-item text-clip"
:class="{current:isCurrent(item.linkPath&&item.linkPath.length?[...item.linkPath,item.path]:[item.path])}"
@click="$router.push(item.path)"
>
<span :style="{ paddingLeft: `${deep*2}em` }">{{ item.menuName }}</span>
</div>
</template>
</li>
</ul>
</template>
<script>
export default {
name: "NavList",
props: {
list: {
type: Array,
required: true,
}, // 导航列表 [ { name: "xxx", path: "xxx" } ]
deep: {
type: Number,
default: 0,
},
highlightParentRule: {
type: Function,
},
},
data() {
return {
showMore: {},
};
},
methods: {
showMoreAction(index) {
let flag = this.showMore[index];
if (flag === undefined) {
flag = true;
}
this.showMore[index] = !flag
},
isCurrent(path) {
return (
(this.highlightParentRule && this.highlightParentRule(path)) || false
);
},
},
};
</script>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment