提交 040cea0f 编写于 作者: aaronchen2k2k's avatar aaronchen2k2k

load sites and its products

上级 24d42169
......@@ -74,6 +74,69 @@ func ListLang() (langs []serverDomain.ZentaoLang, err error) {
return
}
func LoadSiteProduct(currSite serverDomain.ZentaoSite, currProductId int) (
products []serverDomain.ZentaoProduct, currProduct serverDomain.ZentaoProduct, err error) {
if currSite.Id == 0 {
return
}
config := commDomain.WorkspaceConf{
Url: currSite.Url,
Username: currSite.Username,
Password: currSite.Password,
}
if config.Url == "" {
err = errors.New(i118Utils.Sprintf("pls_config_workspace"))
return
}
err = Login(config)
if err != nil {
return
}
url := GenApiUrl("products", nil, config.Url)
bytes, err := httpUtils.Get(url)
if err != nil {
return
}
jsn, err := simplejson.NewJson(bytes)
if err != nil {
return
}
items, err := jsn.Get("products").Array()
if err != nil {
return
}
var first serverDomain.ZentaoProduct
for idx, item := range items {
productMap, _ := item.(map[string]interface{})
id, _ := productMap["id"].(json.Number).Int64()
name, _ := productMap["name"].(string)
product := serverDomain.ZentaoProduct{Id: int(id), Name: name}
if int64(currProductId) == id {
currProduct = product
}
if idx == 0 {
first = product
}
products = append(products, product)
}
if currProduct.Id == 0 && len(items) > 0 { // not found, use the first one
currProduct = first
}
return
}
func ListProduct(workspacePath string) (products []serverDomain.ZentaoProduct, err error) {
config := configUtils.LoadByWorkspacePath(workspacePath)
if config.Url == "" {
......
......@@ -5,10 +5,12 @@ import (
commDomain "github.com/aaronchen2k/deeptest/internal/comm/domain"
zentaoHelper "github.com/aaronchen2k/deeptest/internal/comm/helper/zentao"
serverDomain "github.com/aaronchen2k/deeptest/internal/server/modules/v1/domain"
"github.com/aaronchen2k/deeptest/internal/server/modules/v1/service"
"github.com/kataras/iris/v12"
)
type ZentaoCtrl struct {
SiteService *service.SiteService `inject:""`
BaseCtrl
}
......@@ -19,7 +21,7 @@ func NewZentaoCtrl() *ZentaoCtrl {
func (c *ZentaoCtrl) GetProfile(ctx iris.Context) {
workspacePath := ctx.URLParam("currWorkspace")
if workspacePath == "" {
ctx.JSON(c.SuccessResp(make([]serverDomain.ZentaoProduct, 0)))
ctx.JSON(c.SuccessResp(iris.Map{}))
return
}
......@@ -32,6 +34,22 @@ func (c *ZentaoCtrl) GetProfile(ctx iris.Context) {
ctx.JSON(c.SuccessResp(data))
}
func (c *ZentaoCtrl) listSiteAndProduct(ctx iris.Context) {
currSiteId, _ := ctx.URLParamInt("currSiteId")
currProductId, _ := ctx.URLParamInt("currProductId")
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
}
data := iris.Map{"sites": sites, "currSite": currSite, "products": products, "currProduct": currProduct}
ctx.JSON(c.SuccessResp(data))
}
func (c *ZentaoCtrl) ListProduct(ctx iris.Context) {
workspacePath := ctx.URLParam("currWorkspace")
if workspacePath == "" {
......
......@@ -20,6 +20,13 @@ type ZentaoLang struct {
Name string `json:"name"`
}
type ZentaoSite struct {
Id int `json:"id"`
Name string `json:"name"`
Url string `json:"url"`
Username string `json:"username"`
Password string `json:"password"`
}
type ZentaoProduct struct {
Id int `json:"id"`
Name string `json:"name"`
......
......@@ -42,3 +42,38 @@ func (s *SiteService) Update(site model.Site) (err error) {
func (s *SiteService) Delete(id uint) error {
return s.SiteRepo.Delete(id)
}
func (s *SiteService) LoadSites(currSiteId int) (sites []serverDomain.ZentaoSite, currSite serverDomain.ZentaoSite, err error) {
req := serverDomain.ReqPaginate{PaginateReq: domain.PaginateReq{Page: 1, PageSize: 10000}}
pageData, err := s.Paginate(req)
if err != nil {
return
}
pos := pageData.Result.([]model.Site)
var first serverDomain.ZentaoSite
for idx, item := range pos {
site := serverDomain.ZentaoSite{
Url: item.Url,
Username: item.Username,
Password: item.Password,
}
if uint(currSiteId) == item.ID {
currSite = site
}
if idx == 0 {
first = site
}
sites = append(sites, site)
}
if currSite.Id == 0 { // not found, use the first one
currSite = first
}
return
}
......@@ -24,9 +24,8 @@ export interface SettingsType {
*/
siteTokenKey: string;
/**
* 站点本地存储当前工作目录的Key值
*/
currSiteId: string;
currProductId: string;
currWorkspace: string;
/**
......@@ -50,8 +49,11 @@ const settings: SettingsType = {
topNavEnable: true,
headFixed: true,
siteTokenKey: 'admin_antd_vue_token',
currSiteId: 'currSiteId',
currProductId: 'currProductId',
currWorkspace: 'currWorkspace',
// ajaxHeadersTokenKey: 'x-token',
ajaxHeadersTokenKey: 'Authorization',
ajaxResponseNoVerifyUrl: [
'/account/login', // 用户登录
......
......@@ -11,8 +11,8 @@
</div>
</div>
<div class="top-workspace-wrapper">
<RightTopWorkspace class="top-select-workspace"></RightTopWorkspace>
<div class="top-site-wrapper">
<RightTopSiteProduct></RightTopSiteProduct>
</div>
<div class="menu-wrapper">
......@@ -33,7 +33,7 @@ import { useI18n } from "vue-i18n";
import { BreadcrumbType, RoutesDataItem } from '@/utils/routes';
import RightTopSettings from './RightTopSettings.vue';
import useTopMenuWidth from "../composables/useTopMenuWidth";
import RightTopWorkspace from './RightTopWorkspace.vue';
import RightTopSiteProduct from './RightTopSiteProduct.vue';
import RightTopMenu from './RightTopMenu.vue';
import {useStore} from "vuex";
import {ZentaoData} from "@/store/zentao";
......@@ -53,7 +53,7 @@ export default defineComponent({
name: 'RightTop',
components: {
RightTopSettings,
RightTopWorkspace, RightTopMenu,
RightTopSiteProduct, RightTopMenu,
},
props: {
collapsed: {
......@@ -168,7 +168,7 @@ export default defineComponent({
}
}
.top-workspace-wrapper {
.top-site-wrapper {
margin-right: 16px;
width: 320px;
}
......
<template>
<div>
<!-- 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="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">
<div class="line">
<div class="t-link name" @click="selectSite(item)">{{ item.name }}</div>
</div>
</a-menu-item>
</template>
</a-menu>
</template>
</a-dropdown>
<!-- zentao product selection -->
<a-dropdown
:dropdownMatchSelectWidth="false"
class="dropdown-list">
<a class="t-link-btn" @click.prevent>
<span class="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">
<div class="line">
<div class="t-link name" @click="selectProduct(item)">{{ item.name }}</div>
</div>
</a-menu-item>
</template>
</a-menu>
</template>
</a-dropdown>
</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 SiteProductCreateForm from "@/views/component/workspace/create.vue";
import {hideMenu} from "@/utils/dom";
import {useI18n} from "vue-i18n";
import {ZentaoData} from "@/store/zentao";
interface RightTopSiteProduct {
t: (key: string | number) => string;
sites: ComputedRef<any[]>;
products: ComputedRef<any[]>;
currSite: Ref
currProduct: Ref
selectSite: (item) => void;
selectProduct: (item) => void;
}
export default defineComponent({
name: 'RightTopSiteProduct',
components: {IconSvg},
setup(): RightTopSiteProduct {
const { t } = useI18n();
const router = useRouter();
const store = useStore<{ zentao: ZentaoData }>();
const sites = computed<any[]>(() => store.state.zentao.sites);
const products = computed<any>(() => store.state.zentao.products);
const currSite = computed<any>(() => store.state.zentao.currSite);
const currProduct = computed<any>(() => store.state.zentao.currProduct);
store.dispatch('zentao/fetchSitesAndProducts')
onMounted(() => {
console.log('onMounted')
})
const selectSite = (item): void => {
console.log('selectSite', item)
}
const selectProduct = (item): void => {
console.log('selectProduct', item)
}
return {
t,
selectSite,
selectProduct,
sites,
products,
currSite,
currProduct,
}
}
})
</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;
}
}
}
}
}
</style>
\ No newline at end of file
......@@ -4,43 +4,6 @@
{{ t('create_workspace') }}
</div>
<!-- zentao site selection -->
<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>
<!-- zentao product selection -->
<a-dropdown
v-if="workspaces.length > 0"
:dropdownMatchSelectWidth="false"
......
import request from '@/utils/request';
import {Config} from "@/views/config/data";
import {QueryParams} from "@/types/data";
const apiPath = 'zentao';
const apiPathBug = 'bug';
export async function queryLang(): Promise<any> {
return request({
url: `/${apiPath}/listLang`,
method: 'GET',
});
}
export async function getProfile(): Promise<any> {
return request({
url: `/${apiPath}/getProfile`,
......@@ -11,10 +20,11 @@ export async function getProfile(): Promise<any> {
});
}
export async function queryLang(): Promise<any> {
export async function querySiteAndProduct(params?: QueryParams): Promise<any> {
return request({
url: `/${apiPath}/listLang`,
method: 'GET',
url: `/${apiPath}/listSiteAndProduct`,
method: 'get',
params,
});
}
......
import { Mutation, Action } from 'vuex';
import { StoreModuleType } from "@/utils/store";
import { ResponseData } from '@/utils/request';
import {getProfile, queryLang, queryProduct, queryModule, querySuite, queryTask} from "../services/zentao";
import {queryLang, querySiteAndProduct, getProfile, queryProduct, queryModule, querySuite, queryTask} from "../services/zentao";
import {setCache} from "@/utils/localCache";
import settings from "@/config/settings";
export interface ZentaoData {
profile: any
langs: any[]
profile: any
sites: any[]
products: any[]
currSite: any
currProduct: any
modules: any[]
suites: any[]
tasks: any[]
......@@ -15,16 +23,21 @@ export interface ZentaoData {
export interface ModuleType extends StoreModuleType<ZentaoData> {
state: ZentaoData;
mutations: {
saveProfile: Mutation<any>;
saveLangs: Mutation<any>;
saveProfile: Mutation<any>;
saveSitesAndProducts: Mutation<any>;
saveProducts: Mutation<any>;
saveModules: Mutation<any>;
saveSuites: Mutation<any>;
saveTasks: Mutation<any>;
};
actions: {
getProfile: Action<ZentaoData, ZentaoData>;
fetchLangs: Action<ZentaoData, ZentaoData>;
getProfile: Action<ZentaoData, ZentaoData>;
fetchSitesAndProducts: Action<ZentaoData, ZentaoData>;
fetchProducts: Action<ZentaoData, ZentaoData>;
fetchModules: Action<ZentaoData, ZentaoData>;
fetchSuites: Action<ZentaoData, ZentaoData>;
......@@ -33,9 +46,15 @@ export interface ModuleType extends StoreModuleType<ZentaoData> {
}
const initState: ZentaoData = {
profile: {},
langs: [],
profile: {},
sites: [],
products: [],
currSite: {},
currProduct: {},
modules: [],
suites: [],
tasks: [],
......@@ -48,13 +67,20 @@ const StoreModel: ModuleType = {
...initState
},
mutations: {
saveLangs(state, payload) {
console.log('payload', payload)
state.langs = payload
},
saveProfile(state, payload) {
console.log('payload', payload)
state.profile = payload
},
saveLangs(state, payload) {
console.log('payload', payload)
state.langs = payload
saveSitesAndProducts(state, payload) {
state.sites = payload.sites;
state.products = payload.products;
setCache(settings.currSiteId, payload.currSite.id);
setCache(settings.currProductId, payload.currProduct.id);
},
saveProducts(state, payload) {
console.log('payload', payload)
......@@ -77,12 +103,11 @@ const StoreModel: ModuleType = {
},
},
actions: {
async getProfile({ commit }) {
async fetchLangs({ commit }) {
try {
const response: ResponseData = await getProfile();
const response: ResponseData = await queryLang();
const { data } = response;
// data.avatar = ''
commit('saveProfile', data)
commit('saveLangs', data)
return true;
} catch (error) {
......@@ -90,17 +115,25 @@ const StoreModel: ModuleType = {
}
},
async fetchLangs({ commit }) {
async getProfile({ commit }) {
try {
const response: ResponseData = await queryLang();
const response: ResponseData = await getProfile();
const { data } = response;
commit('saveLangs', data)
// data.avatar = ''
commit('saveProfile', data)
return true;
} catch (error) {
return false;
}
},
async fetchSitesAndProducts({ commit }) {
const response: ResponseData = await querySiteAndProduct();
const { data } = response;
commit('saveSitesAndProducts', data)
return true;
},
async fetchProducts({ commit }) {
const response: ResponseData = await queryProduct();
const { data } = response;
......
......@@ -95,7 +95,15 @@ request.interceptors.request.use(
}
config.params = { ...config.params, ts: Date.now() };
if (!config.params.currWorkspace) {
if (!config.params[settings.currSiteId]) {
const workspacePath = await getCache(settings.currSiteId);
config.params = { ...config.params, currSiteId: workspacePath, 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 };
}
if (!config.params[settings.currWorkspace]) {
const workspacePath = await getCache(settings.currWorkspace);
config.params = { ...config.params, currWorkspace: workspacePath, lang: i18n.global.locale.value };
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册