feat(agent): AgentList.vue 구현 — 총 에이전트 수, 정산 항목별 금액, 합계 표시 및 라우팅 추가
- api: /admin/partner/agent/list 연동을 위한 api/agent.js 추가(getAgentList) - router: 에이전트 상세 및 5종 정산 상세 라우트 추가(파라미터 agentId 사용) - AgentDetail.vue와 정산 상세 5개 뷰(플레이스홀더) 추가 - 숫자/통화 포맷 적용 및 클릭 가능한 스타일 클래스 추가
This commit is contained in:
12
src/api/agent.js
Normal file
12
src/api/agent.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
// 에이전트 리스트 조회
|
||||||
|
// 서버 스펙에 페이지네이션이 없다면 단순 GET으로 사용
|
||||||
|
// 추후 필요 시 params(page,size) 확장 가능
|
||||||
|
async function getAgentList() {
|
||||||
|
return Vue.axios.get('/admin/partner/agent/list')
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getAgentList
|
||||||
|
}
|
||||||
@@ -56,6 +56,42 @@ const routes = [
|
|||||||
name: 'AgentList',
|
name: 'AgentList',
|
||||||
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentList.vue')
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentList.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/agent/:agentId',
|
||||||
|
name: 'AgentDetail',
|
||||||
|
props: true,
|
||||||
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentDetail.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/agent/:agentId/settlement/live',
|
||||||
|
name: 'AgentSettlementLive',
|
||||||
|
props: true,
|
||||||
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentLiveSettlement.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/agent/:agentId/settlement/content',
|
||||||
|
name: 'AgentSettlementContent',
|
||||||
|
props: true,
|
||||||
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentContentSettlement.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/agent/:agentId/settlement/community',
|
||||||
|
name: 'AgentSettlementCommunity',
|
||||||
|
props: true,
|
||||||
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentCommunitySettlement.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/agent/:agentId/settlement/content-donation',
|
||||||
|
name: 'AgentSettlementContentDonation',
|
||||||
|
props: true,
|
||||||
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentContentDonationSettlement.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/agent/:agentId/settlement/channel-donation',
|
||||||
|
name: 'AgentSettlementChannelDonation',
|
||||||
|
props: true,
|
||||||
|
component: () => import(/* webpackChunkName: "agent" */ '../views/Agent/AgentChannelDonationSettlement.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/agent/settlement-ratio',
|
path: '/agent/settlement-ratio',
|
||||||
name: 'AgentSettlementRatio',
|
name: 'AgentSettlementRatio',
|
||||||
|
|||||||
37
src/views/Agent/AgentChannelDonationSettlement.vue
Normal file
37
src/views/Agent/AgentChannelDonationSettlement.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
@click="$router.back()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>에이전트 정산 상세 - 채널 후원</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<h3>채널 후원 정산 상세 페이지 (준비중)</h3>
|
||||||
|
<p>Agent ID: {{ agentId }}</p>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AgentChannelDonationSettlement',
|
||||||
|
props: {
|
||||||
|
agentId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
37
src/views/Agent/AgentCommunitySettlement.vue
Normal file
37
src/views/Agent/AgentCommunitySettlement.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
@click="$router.back()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>에이전트 정산 상세 - 커뮤니티</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<h3>커뮤니티 정산 상세 페이지 (준비중)</h3>
|
||||||
|
<p>Agent ID: {{ agentId }}</p>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AgentCommunitySettlement',
|
||||||
|
props: {
|
||||||
|
agentId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
37
src/views/Agent/AgentContentDonationSettlement.vue
Normal file
37
src/views/Agent/AgentContentDonationSettlement.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
@click="$router.back()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>에이전트 정산 상세 - 콘텐츠 후원</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<h3>콘텐츠 후원 정산 상세 페이지 (준비중)</h3>
|
||||||
|
<p>Agent ID: {{ agentId }}</p>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AgentContentDonationSettlement',
|
||||||
|
props: {
|
||||||
|
agentId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
37
src/views/Agent/AgentContentSettlement.vue
Normal file
37
src/views/Agent/AgentContentSettlement.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
@click="$router.back()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>에이전트 정산 상세 - 콘텐츠</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<h3>콘텐츠 정산 상세 페이지 (준비중)</h3>
|
||||||
|
<p>Agent ID: {{ agentId }}</p>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AgentContentSettlement',
|
||||||
|
props: {
|
||||||
|
agentId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
37
src/views/Agent/AgentDetail.vue
Normal file
37
src/views/Agent/AgentDetail.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
@click="$router.back()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>에이전트 상세</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<h3>에이전트 상세 페이지 (준비중)</h3>
|
||||||
|
<p>Agent ID: {{ agentId }}</p>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AgentDetail',
|
||||||
|
props: {
|
||||||
|
agentId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
@@ -1,19 +1,224 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container fluid>
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-spacer />
|
||||||
|
<v-toolbar-title>에이전트 리스트</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<v-container>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col
|
||||||
<h2>에이전트 리스트</h2>
|
cols="12"
|
||||||
<p>에이전트 목록을 관리합니다. (구현 예정)</p>
|
class="text-right"
|
||||||
|
>
|
||||||
|
총 에이전트 수: <strong>{{ totalCount | numberFormat }}</strong>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-simple-table class="elevation-10">
|
||||||
|
<template>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
에이전트 닉네임
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
소속 크리에이터 수
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
라이브
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
콘텐츠
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
커뮤니티
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
콘텐츠 후원
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
채널 후원
|
||||||
|
</th>
|
||||||
|
<th class="text-center">
|
||||||
|
합계
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="item in agentList"
|
||||||
|
:key="item.agentId"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="link"
|
||||||
|
@click="goAgentDetail(item)"
|
||||||
|
>
|
||||||
|
{{ item.agentNickname }}
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{{ item.assignedCreatorCount | numberFormat }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-right clickable"
|
||||||
|
@click="goSettlement(item, 'live')"
|
||||||
|
>
|
||||||
|
{{ formatCurrency(item.liveAgentSettlementAmount) }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-right clickable"
|
||||||
|
@click="goSettlement(item, 'content')"
|
||||||
|
>
|
||||||
|
{{ formatCurrency(item.contentAgentSettlementAmount) }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-right clickable"
|
||||||
|
@click="goSettlement(item, 'community')"
|
||||||
|
>
|
||||||
|
{{ formatCurrency(item.communityAgentSettlementAmount) }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-right clickable"
|
||||||
|
@click="goSettlement(item, 'content-donation')"
|
||||||
|
>
|
||||||
|
{{ formatCurrency(item.contentDonationAgentSettlementAmount) }}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
class="text-right clickable"
|
||||||
|
@click="goSettlement(item, 'channel-donation')"
|
||||||
|
>
|
||||||
|
{{ formatCurrency(item.channelDonationAgentSettlementAmount) }}
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
{{ formatCurrency(totalAmount(item)) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</template>
|
||||||
|
</v-simple-table>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<!-- 페이지네이션은 서버 지원 시 활성화
|
||||||
|
<v-row class="text-center">
|
||||||
|
<v-col>
|
||||||
|
<v-pagination
|
||||||
|
v-model="page"
|
||||||
|
:length="total_page"
|
||||||
|
circle
|
||||||
|
@input="fetchList"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
-->
|
||||||
</v-container>
|
</v-container>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getAgentList } from '@/api/agent'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AgentList',
|
name: 'AgentList',
|
||||||
|
filters: {
|
||||||
|
numberFormat(v) {
|
||||||
|
if (v === null || v === undefined) return '-'
|
||||||
|
try {
|
||||||
|
return new Intl.NumberFormat('ko-KR').format(v)
|
||||||
|
} catch (e) {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
agentList: [],
|
||||||
|
totalCount: 0,
|
||||||
|
// 페이지네이션(필요 시)
|
||||||
|
page: 1,
|
||||||
|
total_page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
is_loading: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchList() {
|
||||||
|
if (this.is_loading) return
|
||||||
|
this.is_loading = true
|
||||||
|
try {
|
||||||
|
const res = await getAgentList(/* this.page, this.page_size */)
|
||||||
|
// 일부 API는 { data: { totalCount, items } } 형태로 한 번 더 래핑됨을 대비
|
||||||
|
let payload = (res && res.data) ? res.data : null
|
||||||
|
if (payload && payload.data && (!payload.items && !payload.totalCount)) {
|
||||||
|
payload = payload.data
|
||||||
|
}
|
||||||
|
const data = payload || { totalCount: 0, items: [] }
|
||||||
|
this.totalCount = data.totalCount || 0
|
||||||
|
this.agentList = Array.isArray(data.items) ? data.items : []
|
||||||
|
// 서버가 페이지네이션 정보를 주면 설정하도록 남김
|
||||||
|
this.total_page = Math.max(1, Math.ceil(this.totalCount / this.page_size))
|
||||||
|
} catch (e) {
|
||||||
|
this.totalCount = 0
|
||||||
|
this.agentList = []
|
||||||
|
} finally {
|
||||||
|
this.is_loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formatCurrency(n) {
|
||||||
|
const num = Number(n || 0)
|
||||||
|
return new Intl.NumberFormat('ko-KR', { style: 'currency', currency: 'KRW', maximumFractionDigits: 0 }).format(num)
|
||||||
|
},
|
||||||
|
totalAmount(item) {
|
||||||
|
const {
|
||||||
|
liveAgentSettlementAmount = 0,
|
||||||
|
contentAgentSettlementAmount = 0,
|
||||||
|
communityAgentSettlementAmount = 0,
|
||||||
|
contentDonationAgentSettlementAmount = 0,
|
||||||
|
channelDonationAgentSettlementAmount = 0,
|
||||||
|
} = item || {}
|
||||||
|
return (
|
||||||
|
(liveAgentSettlementAmount || 0) +
|
||||||
|
(contentAgentSettlementAmount || 0) +
|
||||||
|
(communityAgentSettlementAmount || 0) +
|
||||||
|
(contentDonationAgentSettlementAmount || 0) +
|
||||||
|
(channelDonationAgentSettlementAmount || 0)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
goAgentDetail(item) {
|
||||||
|
this.$router.push({ name: 'AgentDetail', params: { agentId: item.agentId } })
|
||||||
|
},
|
||||||
|
goSettlement(item, type) {
|
||||||
|
const id = item.agentId
|
||||||
|
const nameMap = {
|
||||||
|
'live': 'AgentSettlementLive',
|
||||||
|
'content': 'AgentSettlementContent',
|
||||||
|
'community': 'AgentSettlementCommunity',
|
||||||
|
'content-donation': 'AgentSettlementContentDonation',
|
||||||
|
'channel-donation': 'AgentSettlementChannelDonation',
|
||||||
|
}
|
||||||
|
const name = nameMap[type]
|
||||||
|
if (!name) return
|
||||||
|
this.$router.push({ name, params: { agentId: id } })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.link {
|
||||||
|
color: #3f51b5;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
37
src/views/Agent/AgentLiveSettlement.vue
Normal file
37
src/views/Agent/AgentLiveSettlement.vue
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dark>
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
@click="$router.back()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>에이전트 정산 상세 - 라이브</v-toolbar-title>
|
||||||
|
<v-spacer />
|
||||||
|
</v-toolbar>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<h3>라이브 정산 상세 페이지 (준비중)</h3>
|
||||||
|
<p>Agent ID: {{ agentId }}</p>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AgentLiveSettlement',
|
||||||
|
props: {
|
||||||
|
agentId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user