提交 3ae54bd2 编写于 作者: aaronchen2k2k's avatar aaronchen2k2k

load sites and its products

上级 1dcc8a83
......@@ -87,6 +87,9 @@ func LoadSiteProduct(currSite serverDomain.ZentaoSite, currProductId int) (
}
products, err = loadProduct(config)
if err != nil {
products = make([]serverDomain.ZentaoProduct, 0)
}
var first serverDomain.ZentaoProduct
for idx, product := range products {
......
......@@ -40,11 +40,7 @@ func (c *ZentaoCtrl) ListSiteAndProduct(ctx iris.Context) {
sites, currSite, _ := c.SiteService.LoadSites(currSiteId)
products, currProduct, err := zentaoHelper.LoadSiteProduct(currSite, currProductId)
if err != nil {
ctx.JSON(c.ErrResp(commConsts.BizErrWorkspaceConfig, err.Error()))
return
}
products, currProduct, _ := zentaoHelper.LoadSiteProduct(currSite, currProductId)
data := iris.Map{"sites": sites, "currSite": currSite, "products": products, "currProduct": currProduct}
ctx.JSON(c.SuccessResp(data))
......
......@@ -56,6 +56,7 @@ func (s *SiteService) LoadSites(currSiteId int) (sites []serverDomain.ZentaoSite
for idx, item := range pos {
site := serverDomain.ZentaoSite{
Id: int(item.ID),
Name: item.Name,
Url: item.Url,
Username: item.Username,
Password: item.Password,
......
......@@ -26,6 +26,7 @@ export interface SettingsType {
currSiteId: string;
currProductId: string;
currProductIdBySite: string;
currWorkspace: string;
/**
......@@ -52,6 +53,7 @@ const settings: SettingsType = {
currSiteId: 'currSiteId',
currProductId: 'currProductId',
currProductIdBySite: 'currProductIdBySite',
currWorkspace: 'currWorkspace',
ajaxHeadersTokenKey: 'Authorization',
......
<template>
<div>
<div v-if="sites.length > 0">
<!-- zentao site selection -->
<a-dropdown
:dropdownMatchSelectWidth="false"
class="dropdown-list">
<a class="t-link-btn" @click.prevent>
<span class="name">{{currSite.name}}</span>
<span class="name">{{ currSite.name }}</span>
<span class="icon2"><icon-svg type="down"></icon-svg></span>
</a>
<template #overlay>
<a-menu class="menu">
<template v-for="item in sites" :key="item.path">
<a-menu-item v-if="currSite.path !== item.path">
<a-menu v-if="sites.length > 1" class="menu">
<template v-for="item in sites" :key="item.id">
<a-menu-item v-if="currSite.id !== item.id">
<div class="line">
<div class="t-link name" @click="selectSite(item)">{{ item.name }}</div>
</div>
......@@ -28,13 +28,13 @@
class="dropdown-list">
<a class="t-link-btn" @click.prevent>
<span class="name">{{currProduct.name}}</span>
<span class="name">{{currProduct.name ? currProduct.name : '无'}}</span>
<span class="icon2"><icon-svg type="down"></icon-svg></span>
</a>
<template #overlay>
<a-menu class="menu">
<template v-for="item in workspaces" :key="item.path">
<a-menu-item v-if="currProduct.path !== item.path">
<a-menu v-if="products.length > 1" class="menu">
<template v-for="item in products" :key="item.id">
<a-menu-item v-if="currProduct.id !== item.id">
<div class="line">
<div class="t-link name" @click="selectProduct(item)">{{ item.name }}</div>
</div>
......@@ -82,17 +82,19 @@ export default defineComponent({
const currSite = computed<any>(() => store.state.zentao.currSite);
const currProduct = computed<any>(() => store.state.zentao.currProduct);
store.dispatch('zentao/fetchSitesAndProducts')
store.dispatch('zentao/fetchSitesAndProducts', {})
onMounted(() => {
console.log('onMounted')
})
const selectSite = (item): void => {
console.log('selectSite', item)
const selectSite = (site): void => {
console.log('selectSite', site)
store.dispatch('zentao/fetchSitesAndProducts', {currSiteId: site.id})
}
const selectProduct = (item): void => {
console.log('selectProduct', item)
const selectProduct = (product): void => {
console.log('selectProduct', product)
store.dispatch('zentao/fetchSitesAndProducts', {currProductId: product.id})
}
return {
......
<template>
<div>
<div v-if="workspaces.length == 0" class="create-link" @click="selectWorkspace('')">
{{ t('create_workspace') }}
</div>
<a-dropdown
v-if="workspaces.length > 0"
:dropdownMatchSelectWidth="false"
class="dropdown-list">
<a class="t-link-btn" @click.prevent>
<span class="name">{{currWorkspace.name}}</span>
<span class="icon2"><icon-svg type="down"></icon-svg></span>
</a>
<template #overlay>
<a-menu class="menu">
<template v-for="item in workspaces" :key="item.path">
<a-menu-item v-if="currWorkspace.path !== item.path">
<div class="line">
<div class="t-link name" @click="selectWorkspace(item)">{{ item.name }}</div>
<div class="space"></div>
<div class="t-link icon" @click="setDeleteModel(item)">
<icon-svg type="delete" class="menu-icon"></icon-svg>
</div>
</div>
</a-menu-item>
</template>
<a-menu-divider v-if="workspaces.length > 1"/>
<a-menu-item key="" class="create">
<span class="t-link name" @click="selectWorkspace('')">
<icon-svg type="add" class="menu-icon"></icon-svg>
{{ t('create_workspace') }}
</span>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<workspace-create-form
:visible="formVisible"
:onCancel="cancel"
:onSubmit="submitForm"
/>
<a-modal
v-model:visible="deleteVisible"
title="Modal"
:ok-text="t('confirm')"
:cancel-text="t('cancel')"
@ok="removeWorkspace"
>
<p>{{t('confirm_delete', {name: deleteModel.path})}}</p>
</a-modal>
</div>
</template>
<script lang="ts">
import {computed, ComputedRef, defineComponent, onMounted, Ref, ref, watch} from "vue";
import {useRouter} from "vue-router";
import {useStore} from "vuex";
import IconSvg from "@/components/IconSvg/index";
import {WorkspaceData} from "@/store/workspace";
import WorkspaceCreateForm from "@/views/component/workspace/create.vue";
import {createWorkspace} from "@/services/workspace";
import {hideMenu} from "@/utils/dom";
import {useI18n} from "vue-i18n";
interface RightTopWorkspace {
t: (key: string | number) => string;
workspaces: ComputedRef<any[]>;
currWorkspace: ComputedRef;
selectWorkspace: (item) => void;
removeWorkspace: (item) => void;
formVisible: Ref<boolean>;
setFormVisible: (val: boolean) => void;
submitForm: (workspace: any) => Promise<void>;
cancel: () => void;
deleteModel: Ref
deleteVisible: Ref<boolean>;
setDeleteModel: (val, model) => void;
}
export default defineComponent({
name: 'RightTopWorkspace',
components: {WorkspaceCreateForm, IconSvg},
setup(): RightTopWorkspace {
const { t } = useI18n();
const router = useRouter();
const store = useStore<{ workspace: WorkspaceData }>();
const workspaces = computed<any[]>(() => store.state.workspace.workspaces);
const currWorkspace = computed<any>(() => store.state.workspace.currWorkspace);
store.dispatch('workspace/fetchWorkspace', '')
const switchWorkspace = (newWorkspace, oldWorkspace) => {
const routerPath = router.currentRoute.value.path
if ( (oldWorkspace.id && oldWorkspace.id !== newWorkspace.id && routerPath.indexOf('/exec/history/') > -1)
|| (newWorkspace.type === 'unit' && (routerPath === '/sync' || routerPath === '/script/list'))) {
router.push(`/exec/history`) // will call hideMenu on this page
} else {
hideMenu(newWorkspace)
}
}
watch(currWorkspace, (newWorkspace, oldWorkspace)=> {
console.log('watch currWorkspace', newWorkspace.type)
switchWorkspace(newWorkspace, oldWorkspace)
}, {deep: true})
onMounted(() => {
console.log('onMounted')
})
const selectWorkspace = (item): void => {
console.log('selectWorkspace', item)
if (!item) {
setFormVisible(true)
} else {
store.dispatch('workspace/fetchWorkspace', item.path)
}
}
let deleteVisible = ref(false)
let deleteModel = ref({} as any)
const setDeleteModel = (model: any) => {
if (model) {
deleteModel.value = model;
deleteVisible.value = true;
} else {
deleteVisible.value = false
}
}
const removeWorkspace = (): void => {
console.log('removeWorkspace', deleteModel)
store.dispatch('workspace/removeWorkspace', deleteModel.value.path).then(() => {
deleteModel.value = {}
deleteVisible.value = false
})
}
const formVisible = ref<boolean>(false);
const setFormVisible = (val: boolean) => {
formVisible.value = val;
};
const submitForm = async (workspace: any) => {
console.log('submitForm', workspace)
createWorkspace(workspace).then(() => {
store.dispatch('workspace/fetchWorkspace', workspace.path);
setFormVisible(false);
}).catch(err => { console.log('') })
}
const cancel = () => {
store.dispatch('workspace/fetchWorkspace', currWorkspace.value.path);
setFormVisible(false);
}
return {
t,
selectWorkspace,
removeWorkspace,
workspaces,
currWorkspace,
formVisible,
setFormVisible,
submitForm,
cancel,
deleteVisible,
deleteModel,
setDeleteModel,
}
}
})
</script>
<style lang="less">
.create-link {
padding: 14px 10px;
width: 150px;
cursor: pointer;
text-align: right;
}
.dropdown-list {
display: inline-block;
margin-right: 26px;
padding-top: 13px;
font-size: 15px !important;
.name {
margin-right: 5px;
}
.icon2 {
.svg-icon {
vertical-align: -3px !important;
}
}
}
.menu {
.ant-dropdown-menu-item {
cursor: default;
.ant-dropdown-menu-title-content {
cursor: default;
.line {
display: flex;
.name {
flex: 1;
margin-top: 3px;
font-size: 16px;
}
.space {
width: 20px;
}
.icon {
width: 15px;
font-size: 16px;
line-height: 28px;
}
}
}
&.create {
text-align: center;
}
}
}
</style>
\ No newline at end of file
import request from '@/utils/request';
import {Config} from "@/views/config/data";
import {QueryParams} from "@/types/data";
import settings from "@/config/settings";
const apiPath = 'zentao';
const apiPathBug = 'bug';
......@@ -20,7 +21,7 @@ export async function getProfile(): Promise<any> {
});
}
export async function querySiteAndProduct(params?: QueryParams): Promise<any> {
export async function querySiteAndProduct(params): Promise<any> {
return request({
url: `/${apiPath}/listSiteAndProduct`,
method: 'get',
......
......@@ -2,7 +2,7 @@ import { Mutation, Action } from 'vuex';
import { StoreModuleType } from "@/utils/store";
import { ResponseData } from '@/utils/request';
import {queryLang, querySiteAndProduct, getProfile, queryProduct, queryModule, querySuite, queryTask} from "../services/zentao";
import {setCache} from "@/utils/localCache";
import {getCache, setCache} from "@/utils/localCache";
import settings from "@/config/settings";
export interface ZentaoData {
......@@ -75,12 +75,19 @@ const StoreModel: ModuleType = {
console.log('payload', payload)
state.profile = payload
},
saveSitesAndProducts(state, payload) {
async saveSitesAndProducts(state, payload) {
state.sites = payload.sites;
state.products = payload.products;
state.currSite = payload.currSite;
state.currProduct = payload.currProduct;
setCache(settings.currSiteId, payload.currSite.id);
setCache(settings.currProductId, payload.currProduct.id);
let mp = await getCache(settings.currProductIdBySite);
if (!mp) mp = {}
mp[payload.currSite.id + ''] = payload.currProduct.id
setCache(settings.currProductIdBySite, mp);
},
saveProducts(state, payload) {
console.log('payload', payload)
......@@ -127,8 +134,9 @@ const StoreModel: ModuleType = {
return false;
}
},
async fetchSitesAndProducts({ commit }) {
const response: ResponseData = await querySiteAndProduct();
async fetchSitesAndProducts({ commit }, payload) {
const response: ResponseData = await querySiteAndProduct(payload);
const { data } = response;
commit('saveSitesAndProducts', data)
......
......@@ -2,11 +2,11 @@
import localforage from 'localforage';
import settings from '@/config/settings';
export const getCache = async (key: string): Promise<string | null> => {
export const getCache = async (key: string): Promise<any | null> => {
return await localforage.getItem(key);
};
export const setCache = async (key: string, val: string): Promise<boolean> => {
export const setCache = async (key: string, val: any): Promise<boolean> => {
try {
await localforage.setItem(key, val);
return true;
......
......@@ -96,16 +96,17 @@ request.interceptors.request.use(
config.params = { ...config.params, ts: Date.now() };
if (!config.params[settings.currSiteId]) {
const workspacePath = await getCache(settings.currSiteId);
config.params = { ...config.params, currSiteId: workspacePath, lang: i18n.global.locale.value };
const currSiteId = await getCache(settings.currSiteId);
config.params = { ...config.params, [settings.currSiteId]: currSiteId, lang: i18n.global.locale.value };
}
if (!config.params[settings.currProductId]) {
const workspacePath = await getCache(settings.currProductId);
config.params = { ...config.params, currProductId: workspacePath, lang: i18n.global.locale.value };
const mp = await getCache(settings.currProductIdBySite);
const currProductId = mp ? mp[config.params[settings.currSiteId]] : 0
config.params = { ...config.params, [settings.currProductId]: currProductId, lang: i18n.global.locale.value };
}
if (!config.params[settings.currWorkspace]) {
const workspacePath = await getCache(settings.currWorkspace);
config.params = { ...config.params, currWorkspace: workspacePath, lang: i18n.global.locale.value };
config.params = { ...config.params, [settings.currWorkspace]: workspacePath, lang: i18n.global.locale.value };
}
console.log('=== request ===', config.url, config)
......
......@@ -49,6 +49,7 @@ const useForm = Form.useForm;
import {useStore} from "vuex";
import {StateType} from "@/views/site/store";
import {ZentaoData} from "@/store/zentao";
interface SiteFormSetupData {
t: (key: string | number) => string;
......@@ -70,6 +71,8 @@ export default defineComponent({
const { t } = useI18n();
const router = useRouter();
const zentaoStore = useStore<{ zentao: ZentaoData }>();
const store = useStore<{ Site: StateType }>();
const modelRef = computed(() => store.state.Site.detailResult);
......@@ -113,10 +116,10 @@ export default defineComponent({
.then(() => {
console.log(modelRef.value);
store.dispatch('Site/save', modelRef.value).then((success) => {
if (success) {
zentaoStore.dispatch('zentao/fetchSitesAndProducts').then((success) => {
notification.success({ message: t('save_success') });
router.push(`/site/list`)
}
})
})
})
.catch((e) => {console.log('')})
......
......@@ -61,7 +61,7 @@
import {computed, ComputedRef, defineComponent, onMounted, ref, Ref, watch} from "vue";
import {useStore} from "vuex";
import {Empty, Form, message, Modal} from "ant-design-vue";
import {Empty, Form, message, Modal, notification} from "ant-design-vue";
import { PlusCircleOutlined } from '@ant-design/icons-vue';
import {StateType} from "./store";
......@@ -70,6 +70,7 @@ import {momentUtcDef} from "@/utils/datetime";
import {useI18n} from "vue-i18n";
import {PaginationConfig, QueryParams} from "@/types/data";
import debounce from "lodash.debounce";
import {ZentaoData} from "@/store/zentao";
const useForm = Form.useForm;
......@@ -159,6 +160,7 @@ export default defineComponent({
]);
const router = useRouter();
const zentaoStore = useStore<{ zentao: ZentaoData }>();
const store = useStore<{ Site: StateType }>();
const models = computed<any[]>(() => store.state.Site.queryResult.result);
const pagination = computed<PaginationConfig>(() => store.state.Site.queryResult.pagination);
......@@ -193,14 +195,15 @@ export default defineComponent({
title: t('confirm_to_delete_site'),
okText: t('confirm'),
cancelText: t('cancel'),
onOk: async () => {
onOk: () => {
removeLoading.value = [id];
const res: boolean = await store.dispatch('Site/delete', id);
if (res === true) {
message.success(t('delete_success'));
await getList(pagination.value.page);
}
removeLoading.value = [];
store.dispatch('Site/delete', id).then((success) => {
zentaoStore.dispatch('zentao/fetchSitesAndProducts').then((success) => {
message.success(t('delete_success'));
getList(pagination.value.page)
removeLoading.value = [];
})
})
}
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册