搜索结果列表页面开发
This commit is contained in:
373
src/components/BranchAdd/index.vue
Normal file
373
src/components/BranchAdd/index.vue
Normal file
@@ -0,0 +1,373 @@
|
||||
<template>
|
||||
<d-modal v-model="vModels" class="branch-add-modal" :before-close="handleCancel">
|
||||
<template #header>
|
||||
<gc-modal-header>
|
||||
<span class="text-G900 text-base font-bold leading-[24px]">新建分支</span>
|
||||
</gc-modal-header>
|
||||
<div class="line bg-G200"></div>
|
||||
</template>
|
||||
<div class="invi-modal-body pt-20 px-24">
|
||||
<d-form ref="branchFormRef" layout="vertical" :rules="rules" :data="branchForm">
|
||||
<d-form-item field="ref" label="基于">
|
||||
<div>
|
||||
<div class="g-branch-compare-content">
|
||||
<div ref="ele" class="g-branch-compare-repo">
|
||||
<div class="g-branch-compare-custom-icon">
|
||||
<slot name="repo-prefix">
|
||||
<Icon :name="repoIcon" :size="repoIconSize"></Icon>
|
||||
</slot>
|
||||
</div>
|
||||
<d-editable-select class="g-branch-compare-select" v-model="repoName" :options="repoList"
|
||||
:disabled="true">
|
||||
<template #item="{ option, index }">
|
||||
<div class="g-branch-compare-option">
|
||||
<slot name="repo-option" :data="option" :index="index">
|
||||
<Icon :name="repoIcon" :size="repoIconSize"></Icon>
|
||||
<div class="g-branch-compare-label">{{ option.label }}</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
</d-editable-select>
|
||||
</div>
|
||||
<div class="g-branch-compare-branch">
|
||||
<div class="g-branch-compare-custom-icon">
|
||||
<slot name="branch-prefix">
|
||||
<Icon :name="branchIcon" :size="branchIconSize" />
|
||||
</slot>
|
||||
</div>
|
||||
<BranchSelector v-model="branchForm.ref" type="branch" :branch="branch" :repoId="repoId" :branchParams="{
|
||||
branch_type: ''
|
||||
}" :isCommits="isCommits"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</d-form-item>
|
||||
<d-form-item field="branch" label="分支名称" :rules="[{ required: true, message: '分支名称不能为空', trigger: 'blur' }]">
|
||||
<d-input v-model="branchForm.branch" placeholder="请输入分支名称" maxlength="200" />
|
||||
</d-form-item>
|
||||
<div v-if="prompt" class="mt-[-16px] text-[#c7000b]">{{ prompt }}</div>
|
||||
<d-form-item field="description" label="描述" class="mb-0">
|
||||
<d-textarea v-model="branchForm.description" :rows="5" placeholder="请补充分支的描述信息" show-count
|
||||
maxlength="2000"></d-textarea>
|
||||
</d-form-item>
|
||||
</d-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="g-modal-footer">
|
||||
<d-button @click="handleCancel">取消</d-button>
|
||||
<d-button :disabled="isConfirm" variant="solid" color="primary" :loading="loading"
|
||||
@click="handleConfirm">确认</d-button>
|
||||
</div>
|
||||
</template>
|
||||
</d-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch, computed, provide } from 'vue';
|
||||
import { useModel } from '@/utils/hooks/useModel';
|
||||
import { getBranches, createBranches } from '@/api/branch';
|
||||
import { useResizeObserver } from '@vueuse/core';
|
||||
import getRepoId from '@/utils/getRepoId';
|
||||
import { getRepoName } from '@/utils/index';
|
||||
import { Message } from 'vue-devui/message';
|
||||
import BranchSelector from '@/components/BranchTagSelector/SingleSelector.vue';
|
||||
import { repoInfoStore } from '@/stores/Repo';
|
||||
import { branchNameRegExp, tagNamePrefixHeadsRegExp, tagNamePrefixRemotesRegExp } from '@/utils/regex';
|
||||
|
||||
const repoId = ref(getRepoId());
|
||||
const branchFormRef = ref<any>(null);
|
||||
|
||||
const repoName = getRepoName();
|
||||
const { getRepoInfo } = repoInfoStore();
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue?: boolean
|
||||
'onUpdate:modelValue'?: Function
|
||||
branches?: string[]
|
||||
options?: { name: string, value: string }[],
|
||||
branch?: string;
|
||||
repoIcon?: string;
|
||||
branchIcon?: string;
|
||||
repoIconSize?: string;
|
||||
branchIconSize?: string;
|
||||
repoReadonly?: boolean;
|
||||
maxHeight?: number;
|
||||
isCommits?: boolean
|
||||
}>(), {
|
||||
data: () => {
|
||||
return {
|
||||
repoId: null,
|
||||
sourceId: null,
|
||||
targetId: null
|
||||
};
|
||||
},
|
||||
branchList: () => [],
|
||||
repoIcon: 'version-history',
|
||||
branchIcon: 'gt-branches',
|
||||
repoIconSize: '16px',
|
||||
branchIconSize: '16px',
|
||||
repoReadonly: true,
|
||||
maxHeight: 250
|
||||
|
||||
});
|
||||
const emits = defineEmits(['confirm', 'update:modelValue']);
|
||||
|
||||
const branchForm = reactive({
|
||||
ref: props.branch || '',
|
||||
branch: '',
|
||||
description: ''
|
||||
});
|
||||
watch(() => props.branch, val => {
|
||||
branchForm.ref = val;
|
||||
});
|
||||
const checkRepoNameRule = (rule: object, value: string, callback: Function) => {
|
||||
if (!branchNameRegExp.test(value)) {
|
||||
return callback(new Error('分支名称由字母、数字-_和/组成;且/不能连续,分支名称必须以字母或数字开头,分支名称最多可以包含 200 个字符。'));
|
||||
} else if (!tagNamePrefixRemotesRegExp.test(value)) {
|
||||
return callback(new Error('格式错误,请勿以"refs/remotes/"开头'));
|
||||
} else if (!tagNamePrefixHeadsRegExp.test(value)) {
|
||||
return callback(new Error('格式错误,请勿以"refs/heads/"开头'));
|
||||
}
|
||||
return callback();
|
||||
};
|
||||
const rules = {
|
||||
ref: [{ required: true, message: '基于分支不能为空', trigger: 'blur' }],
|
||||
branch: [{ validator: checkRepoNameRule }, { required: true, message: '分支名称不能为空', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
const { vModels } = useModel(props, emits);
|
||||
|
||||
const repoList = ref([]);
|
||||
|
||||
const ele = ref(null);
|
||||
const selectWidth = ref(0);
|
||||
const { stop } = useResizeObserver(ele, (entries) => {
|
||||
const entry = entries[0];
|
||||
const { width } = entry.contentRect;
|
||||
selectWidth.value = width;
|
||||
});
|
||||
|
||||
const handleCancel = () => {
|
||||
resetForm();
|
||||
vModels.value = false;
|
||||
};
|
||||
const resetForm = () => {
|
||||
branchForm.ref = '';
|
||||
branchForm.branch = '';
|
||||
branchForm.description = '';
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
const handleConfirm = () => {
|
||||
branchFormRef.value.validate(async(isValid: any, invalidFields: any) => {
|
||||
if (!isValid) return;
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const params = {
|
||||
repoId: repoId.value,
|
||||
ref: branchForm.ref,
|
||||
branch: branchForm.branch,
|
||||
description: branchForm.description
|
||||
};
|
||||
const { error } = await createBranches(params);
|
||||
if (!error) {
|
||||
emits('confirm', params.branch);
|
||||
resetForm();
|
||||
vModels.value = false;
|
||||
Message.success('分支创建成功');
|
||||
// 更新顶部tag信息
|
||||
getRepoInfo();
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const isConfirm = computed(() => {
|
||||
if (branchForm.branch && branchForm.ref) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
watch(() => vModels.value, () => {
|
||||
branchForm.ref = props.branch;
|
||||
});
|
||||
const prompt = ref('');
|
||||
const bOptions = ref();
|
||||
provide('bOptions', bOptions);
|
||||
watch(() => branchForm.branch, val => {
|
||||
const bstr = val.split('/');
|
||||
const b = bOptions.value.find((item: any) => item.name === bstr[0]);
|
||||
if (b) {
|
||||
prompt.value = bstr[0] + '分支已存在';
|
||||
} else {
|
||||
prompt.value = '';
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$g-branch-compare-border-color: var(--color-G300);
|
||||
$g-branch-compare-border-color-hover: var(--color-CG900);
|
||||
$g-branch-compare-border-color-focus: var(--color-link);
|
||||
$g-branch-compare-border-radius: 3px;
|
||||
$g-branch-compare-color: var(--color-CG900);
|
||||
$g-branch-compare-select-bg-color: linear-gradient(180deg, #FCFCFC 0%, #F8F9FB 100%);
|
||||
|
||||
.g-branch-compare {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
|
||||
&-tip {
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
&-box {
|
||||
flex: 1;
|
||||
border: 1px solid $g-branch-compare-border-color;
|
||||
border-radius: $g-branch-compare-border-radius;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-header {
|
||||
padding: 24px 32px 20px 32px;
|
||||
}
|
||||
|
||||
&-content {
|
||||
padding: 0px 0px 0 0px;
|
||||
}
|
||||
|
||||
&-repo {
|
||||
position: relative;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&-branch {
|
||||
position: relative;
|
||||
|
||||
}
|
||||
|
||||
&-custom-icon {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
line-height: 38px;
|
||||
padding-left: 16px;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
|
||||
:deep(.icon) {
|
||||
align-self: center;
|
||||
color: $g-branch-compare-color !important;
|
||||
}
|
||||
|
||||
:deep(.devui-icon__container) {
|
||||
align-self: center;
|
||||
color: $g-branch-compare-color !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
color: $g-branch-compare-color;
|
||||
}
|
||||
|
||||
&-select {
|
||||
:deep(.devui-editable-select-input__wrapper) {
|
||||
background: $g-branch-compare-select-bg-color;
|
||||
}
|
||||
|
||||
:deep(.devui-editable-select-input__inner) {
|
||||
color: $g-branch-compare-color;
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
:deep(.devui-editable-select__item) {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-label {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
&-switch {
|
||||
margin: 0 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: $g-branch-compare-border-radius;
|
||||
background: linear-gradient(180deg, #FCFCFC 0%, #F8F9FB 100%);
|
||||
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.05);
|
||||
border: 1px solid var(--color-CG400);
|
||||
display: flex;
|
||||
|
||||
:deep(.icon) {
|
||||
margin: 0 auto;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.devui-form__label--required:before) {
|
||||
content: "*";
|
||||
color: var(--color-danger);
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
margin-left: -12px
|
||||
}
|
||||
|
||||
:deep(.devui-select__input) {
|
||||
color: $g-branch-compare-color;
|
||||
padding-left: 36px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.invi-modal-body {
|
||||
}
|
||||
|
||||
.branch-add-modal {
|
||||
width: 410px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 0;
|
||||
|
||||
.devui-modal__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
// @apply text-G900 px-[22px] my-[18px] leading-[28px] break-all;
|
||||
}
|
||||
|
||||
.devui-modal__header {
|
||||
padding: 14px 24px;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
right: 24px;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user