aslan-h5/src/views/AgencyCenterView.vue

1138 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="agency-center gradient-background-circles">
<!-- 使用 GeneralHeader 替换 MobileHeader -->
<GeneralHeader
:title="t('agency_center')"
:isHomePage="true"
:showLanguageList="true"
color="black"
style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); z-index: 999"
/>
<div class="content">
<!-- 身份 -->
<div style="display: flex; justify-content: space-between">
<div
style="
margin: 0 1%;
margin-bottom: 12px;
font-weight: 600;
display: flex;
align-items: center;
font-size: 1.3em;
"
>
{{ t('my_account') }}
<img src="../assets/icon/agency.png" alt="" height="20px" style="margin-left: 10px" />
</div>
<img @click="goToNotification" src="../assets/icon/bell.png" height="20px" alt="" />
</div>
<!-- 用户信息卡片 -->
<div
style="
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
margin-bottom: 12px;
display: flex;
flex-direction: column;
justify-content: space-between;
"
>
<!-- 头像信息 -->
<div style="display: flex; align-items: center; margin-bottom: 12px">
<div class="avatar">
<img
v-if="userInfo.userAvatar"
:src="userInfo.userAvatar"
:alt="userInfo.name"
@error="handleImageError"
/>
<span v-else class="avatar-placeholder">{{ getAvatarPlaceholder() }}</span>
</div>
<div style="flex: 1">
<div style="margin: 0 0 4px 0; font-size: 16px; font-weight: 600; color: #333">
{{ userInfo.userNickname || userInfo.name }}
</div>
<div style="margin: 0; font-size: 14px; color: #666">
<span style="display: flex; align-items: center">
<span>ID</span>
<span style="margin: 0 2px">:</span>
<span>{{ userInfo.id }}</span>
</span>
</div>
</div>
<button
style="width: 32px; height: 32px; border: none; background: none; font-size: 16px"
@click="gotoEdit"
>
<img src="../assets/icon/edit.png" alt="" width="70%" />
</button>
</div>
<!-- 我的薪资 -->
<div>
<div style="display: flex; justify-content: space-between; margin-bottom: 5px">
<div style="font-weight: 600">{{ t('my_salary') }}</div>
<button
style="
font-weight: 500;
color: rgba(0, 0, 0, 0.4);
border: 0;
background-color: transparent;
"
@click="goToPersonalSalary"
>
{{ t('personal_salary') }} >
</button>
</div>
</div>
<!-- 历史薪资 -->
<div style="display: grid; grid-template-columns: repeat(2, 1fr)">
<div>
<div style="font-weight: 500; color: rgba(0, 0, 0, 0.4); margin-bottom: 5px">
{{ t('history_salary') }}
</div>
<div style="font-weight: 600">${{ salaryInfo.hostSalary }}</div>
</div>
<div>
<div style="font-weight: 500; color: rgba(0, 0, 0, 0.4); margin-bottom: 5px">
{{ t('current_salary') }}
</div>
<div style="font-weight: 600">${{ salaryInfo.currentSalary }}</div>
</div>
</div>
</div>
<div style="display: flex; justify-content: space-between; align-items: center">
<!-- 标签选项 -->
<div style="display: flex; margin: 5px 0; padding: 5px 0; position: relative">
<div
style="padding: 0 5px"
:class="[taskTab === 'host' ? 'TabActive' : 'TabNoActive']"
@click="taskTab = 'host'"
ref="tabHost"
>
{{ t('host') }}
</div>
<div
style="padding: 0 5px"
:class="[taskTab === 'agency' ? 'TabActive' : 'TabNoActive']"
@click="taskTab = 'agency'"
ref="tabAgency"
>
{{ t('agency') }}
</div>
<!-- 下划线元素 -->
<!-- <div
style="
width: 15px;
height: 3px;
background-color: #bb92ff;
position: absolute;
bottom: 0;
transition: left 0.3s ease;
"
:style="underlineStyle"
></div> -->
</div>
<!-- help -->
<img
src="../assets/icon/helpPurple.png"
alt=""
class="help-btn"
@click.stop="goToInviteMembers"
/>
</div>
<!-- 标签内容 -->
<div>
<div v-if="taskTab === 'host'">
<div
style="
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 5px;
background-color: white;
padding: 3%;
border-radius: 12px;
margin: 0 1%;
margin-bottom: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
"
>
<div style="display: flex; justify-content: space-between">
<div style="font-weight: 600">{{ t('todays_task') }}</div>
<button
style="
font-weight: 500;
color: rgba(0, 0, 0, 0.4);
border: 0;
background-color: transparent;
"
@click="goToPlatformPolicy"
>
{{ t('platform_policy') }} >
</button>
</div>
<div style="display: flex">
<div style="flex: 1">
<div
style="
width: max-content;
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
"
>
<div style="font-weight: 600">{{ t('host_type') }}</div>
<div style="font-weight: 600">{{ taskInfo.anchorType }}</div>
</div>
</div>
<div
style="
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
"
>
<div style="font-weight: 600">{{ t('minutes') }}</div>
<div style="font-weight: 600">
{{ taskInfo.minutesProgress }}/{{ taskInfo.minutesTotal }}
</div>
</div>
<div style="flex: 1; display: flex; justify-content: flex-end">
<div
style="
width: max-content;
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
"
>
<div style="font-weight: 600">{{ t('gift_task') }}</div>
<div style="font-weight: 600">{{ taskInfo.giftTask }}</div>
</div>
</div>
</div>
</div>
<!-- 进度信息 -->
<workReportBox
style="margin-bottom: 10px"
:type="progressInfo.status"
:date="progressInfo.date"
:target="String(progressInfo.target)"
:salary="progressInfo.salary"
:income="progressInfo.income"
:days="String(progressInfo.timeDays)"
></workReportBox>
</div>
<div v-else>
<div
style="
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 5px;
background-color: white;
padding: 3%;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
"
>
<div style="display: flex; justify-content: space-between">
<div style="font-weight: 600">
{{ teamBillInfo.date }}
</div>
<button
style="
font-weight: 500;
color: rgba(0, 0, 0, 0.4);
border: 0;
background-color: transparent;
"
@click="goToTeamBill"
>
{{ t('team_bill') }} >
</button>
</div>
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px">
<div class="contentText">
{{ t('host_salary') }} {{ loadingTeamBill ? '' : teamBillInfo.hostSalary }}
</div>
<div class="contentText">
{{ t('agent_salary') }} {{ loadingTeamBill ? '' : teamBillInfo.agentSalary }}
</div>
<div class="contentText">
{{ t('total') }} {{ loadingTeamBill ? '' : teamBillInfo.total }}
</div>
<div style="display: flex; justify-content: flex-end">
<div
style="
margin: 4px;
padding: 0 8px;
border-radius: 4px;
display: flex;
align-items: center;
"
:style="{ boxShadow }"
>
<div style="font-weight: 500" :style="{ color }">
{{ loadingTeamBill ? '' : teamBillInfo.status }}
</div>
</div>
</div>
</div>
</div>
<div v-if="taskTab === 'agency'" class="team-member-section">
<div class="team-member-card" @click="goToTeamMember">
<div class="card-content">
<div class="member-title">
{{ t('team_member') }}
<span v-if="loadingMemberCount">({{ t('loading') }}...)</span>
<span v-else class="member-title">({{ teamMemberCount }})</span>
</div>
<span class="arrow">></span>
</div>
</div>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="action-buttons">
<button class="action-btn exchange-btn" @click="exchangeGoldCoins">
{{ t('exchange') }}
</button>
<button class="action-btn transfer-btn" @click="transfer">
{{ t('transfer') }}
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import GeneralHeader from '@/components/GeneralHeader.vue'
import { usePageInitializationWithConfig } from '@/utils/pageConfig.js'
import { getTeamId, getUserId } from '@/utils/userStore.js'
import { getTeamMemberCount, getTeamBill, getTeamMemberWork } from '@/api/teamBill.js'
import { clearSelectedPayee } from '../utils/payeeStore.js'
import workReportBox from '@/components/HostCenter/workReportBox.vue'
import { setDocumentDirection } from '@/locales/i18n'
const { t, locale } = useI18n()
const router = useRouter()
// 监听语言变化并设置文档方向
locale.value && setDocumentDirection(locale.value)
// 任务标签
const taskTab = ref('host')
const tabHost = ref(null)
const tabAgency = ref(null)
// 进度信息
const progressInfo = reactive({
date: '',
status: '',
target: '',
salary: '',
timeDays: '',
hostSalary: '',
agentSalary: '',
total: '',
})
// 样式
const color = ref('')
const boxShadow = ref('')
// 团队成员数量
const teamMemberCount = ref(0)
const loadingMemberCount = ref(false)
// Team Bill 信息
const teamBillInfo = reactive({
date: '',
hostSalary: '',
agentSalary: '',
total: '',
status: '',
})
const loadingTeamBill = ref(false)
const underlineStyle = computed(() => {
console.log('计算属性')
let activeTab = taskTab.value == 'host' ? tabHost.value : tabAgency.value
console.log('选中元素的左边距', activeTab?.offsetLeft)
return {
left: `${activeTab?.offsetLeft + activeTab?.offsetWidth / 2 - 15 / 2}px`,
}
})
// 获取成员工作数据
const fetchMemberWorkData = async () => {
try {
const userId = getUserId()
if (!userId) {
console.warn('No user ID available')
return
}
const response = await getTeamMemberWork(userId)
if (response && response.status && response.body) {
const data = response.body
// 取第一条target数据最新的工作数据
if (data.targets && data.targets.length > 0) {
const latestTarget = data.targets[0]
// 格式化日期202508 -> 08/2025
const billBelong = latestTarget.billBelong.toString()
const year = billBelong.substring(0, 4)
const month = billBelong.substring(4, 6)
// 格式化状态
const formatStatus = (status) => {
const statusMap = {
SETTLED: 'Completed',
UNPAID: 'In Progress',
HANG_UP: 'Out of account',
PAY_OUT: 'Completed',
}
return statusMap[status] || status
}
// 获取level值
const level =
latestTarget.target?.settlementResult?.level || latestTarget.target?.level || ''
// 更新数据
Object.assign(progressInfo, {
date: `${month}.${year}`,
status: formatStatus(latestTarget.status),
target: level,
salary: latestTarget.target?.settlementResult?.ownSalary?.toFixed(2) || '',
income: latestTarget.target?.settlementResult?.acceptGiftValue,
timeDays: latestTarget.target?.effectiveDay || '',
})
} else {
console.warn('No targets data available')
}
} else {
console.warn('No member work data available')
}
} catch (error) {
console.error('Failed to fetch member work data:', error)
}
}
watch(
() => teamBillInfo?.status,
(newStatus) => {
if (newStatus == t('in_progress')) {
boxShadow.value = '0 0 1px 0 #6085FF'
color.value = 'rgba(61, 115, 255, 1)'
}
if (newStatus == t('pending')) {
boxShadow.value = '0 0 1px 0 #FF6062'
color.value = 'rgba(255, 61, 64, 1)'
}
if (newStatus == t('completed')) {
boxShadow.value = '0 0 1px 0 #60FF65'
color.value = 'rgba(61, 255, 84, 1)'
}
if (newStatus == t('out_of_account')) {
boxShadow.value = '0 0 1px 0 #6A6161'
color.value = 'rgba(174, 174, 174, 1)'
}
return
}
)
// 页面跳转方法
const goToNotification = () => {
router.push('/message')
}
const gotoEdit = () => {
router.push('/agency-setting')
}
const goToInviteMembers = () => {
router.push('/invite-members')
}
const goToTeamBill = () => {
router.push('/team-bill')
}
const goToTeamMember = () => {
router.push({
path: '/team-member',
query: { source: 'agency-center', members: teamMemberCount.value },
})
}
const exchangeGoldCoins = () => {
router.push('/exchange-gold-coins')
}
const transfer = () => {
router.push('/transfer')
}
const goToPersonalSalary = () => {
router.push('/history-salary')
}
const goToPlatformPolicy = () => {
router.push('/platform-salary?from=agencycenter')
}
// 获取团队成员数量
const fetchTeamMemberCount = async () => {
try {
loadingMemberCount.value = true
const teamId = getTeamId()
if (teamId) {
const response = await getTeamMemberCount(teamId)
if (response.status && response.body) {
teamMemberCount.value = response.body.memberQuantity
} else {
teamMemberCount.value = 0
}
}
} catch (error) {
console.error('Failed to fetch team member count:', error)
teamMemberCount.value = 87 // 出错时使用默认值
} finally {
loadingMemberCount.value = false
}
}
// 获取团队账单数据
const fetchTeamBillData = async () => {
try {
loadingTeamBill.value = true
const teamId = getTeamId()
if (!teamId) {
console.warn('No team ID available')
return
}
const response = await getTeamBill(teamId)
if (response.status && response.body && Array.isArray(response.body)) {
// 取第一条数据(最新的账单)
const latestBill = response.body[0]
if (latestBill) {
// 格式化日期202508 -> 08/2025
const billBelong = latestBill.billBelong.toString()
const year = billBelong.substring(0, 4)
const month = billBelong.substring(4, 6)
// 格式化状态
const formatStatus = (status) => {
const statusMap = {
SETTLED: t('completed'),
UNPAID: t('in_progress'),
HANG_UP: t('out_of_account'),
PAY_OUT: t('completed'),
}
return statusMap[status] || status
}
// 更新数据
Object.assign(teamBillInfo, {
date: `${year}.${month}`,
hostSalary: latestBill.settleResult?.memberSalary?.toFixed(2) || '',
agentSalary: latestBill.settleResult?.ownSalary?.toFixed(2) || '',
total: latestBill.settleResult?.totalSalary?.toFixed(2) || '',
status: formatStatus(latestBill.status),
})
}
} else {
console.warn('No team bill data available')
}
} catch (error) {
console.error('Failed to fetch team bill data:', error)
} finally {
loadingTeamBill.value = false
}
}
const { userInfo, salaryInfo, taskInfo, handleImageError, getAvatarPlaceholder } =
usePageInitializationWithConfig('AGENCY_CENTER', {
needsTeamInfo: true,
forceRefresh: true, // 强制刷新
onDataLoaded: () => {
fetchTeamMemberCount()
fetchTeamBillData() // 新增:获取团队账单数据
fetchMemberWorkData() // 新增:获取成员工作数据
},
})
onMounted(() => {
underlineStyle.value // 触发计算属性更新
clearSelectedPayee() //清除选中的收款人
})
</script>
<style scoped>
* {
color: rgba(0, 0, 0, 0.8);
font-family: 'SF Pro Text';
}
.contentText {
font-weight: 700;
font-size: 1em;
}
.TabActive {
font-weight: 600;
}
.TabNoActive {
font-weight: 500;
color: rgba(0, 0, 0, 0.4);
}
.agency-center {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
.content {
padding: 16px;
position: relative;
z-index: 2;
}
/* 用户信息卡片 */
.user-card {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 25px;
background-color: #8b5cf6;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: 600;
margin-right: 12px;
overflow: hidden;
position: relative;
}
.avatar img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 25px;
}
.avatar .avatar-placeholder {
color: white;
font-size: 20px;
font-weight: 600;
}
.user-details {
flex: 1;
}
.user-details h3 {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.user-details p {
margin: 0;
font-size: 14px;
color: #666;
}
.notification-btn {
width: 32px;
height: 32px;
border: none;
background: none;
font-size: 16px;
cursor: pointer;
}
.account-tags {
display: flex;
gap: 8px;
}
.tag {
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 600;
}
.agency-tag {
background-color: #dbeafe;
color: #1e40af;
}
/* Host Agency 标签页 */
.host-agency-tabs {
display: flex;
background-color: white;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* My salary 区域 */
.salary-section {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.salary-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.salary-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.personal-salary-btn {
background: none;
border: none;
color: #8b5cf6;
font-size: 14px;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
transition: all 0.2s;
}
.personal-salary-btn:hover {
color: #7c3aed;
}
.salary-content {
display: flex;
align-items: center;
gap: 20px;
}
.salary-item {
flex: 1;
text-align: center;
}
.salary-label {
margin: 0 0 8px 0;
font-size: 14px;
color: #666;
}
.salary-amount {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #333;
}
.salary-separator {
width: 1px;
height: 40px;
background-color: #8b5cf6;
}
/* Host Agency 内容区域 */
.host-agency-content {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 任务区域头部样式 */
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.task-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.task-content h3 {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
/* Team Member 独立区域 */
.team-member-section {
margin-bottom: 12px;
}
.team-member-card {
background-color: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.2s;
border: 1px solid #e5e7eb;
}
.team-member-card:active {
transform: scale(0.98);
}
.team-member-card .card-content {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 任务表格 */
.task-table {
border: 1px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
margin-bottom: 12px;
}
.table-row {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.table-header {
background-color: #f8f9fa;
border-bottom: 1px solid #e5e7eb;
}
.table-data {
background-color: white;
}
.table-cell {
padding: 12px 8px;
text-align: center;
border-right: 1px solid #e5e7eb;
font-size: 14px;
}
.table-cell:last-child {
border-right: none;
}
.table-header .table-cell {
font-weight: 600;
color: #374151;
}
.table-data .table-cell {
color: #111827;
}
.minutes-progress {
color: #6b7280;
}
.minutes-completed {
color: #10b981;
font-weight: 600;
}
/* Agency 卡片区域 */
.agency-task-content {
display: flex;
flex-direction: column;
gap: 12px;
}
/*.team-bill-card {
background-color: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
cursor: pointer;
transition: all 0.2s;
border: 2px solid #3B82F6;
}*/
.team-bill-card:active {
transform: scale(0.98);
}
.team-bill-card .card-content {
padding: 16px;
position: relative;
}
/* 通用卡片内容样式 */
.card-content {
padding: 16px;
}
.card-date {
font-size: 18px;
font-weight: 600;
color: #1f2937;
margin-bottom: 8px;
}
.card-link {
position: absolute;
top: 16px;
right: 16px;
display: flex;
align-items: center;
gap: 4px;
color: #8b5cf6;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: color 0.2s;
}
.card-link:hover {
color: #7c3aed;
}
.card-link .arrow {
font-size: 16px;
font-weight: bold;
}
.card-details {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
.detail-row {
display: grid;
grid-template-columns: auto auto auto auto;
gap: 16px;
align-items: center;
}
.detail-label {
font-size: 14px;
color: #6b7280;
}
.detail-value {
font-size: 14px;
font-weight: 500;
color: #1f2937;
}
.status-badge {
background-color: #dbeafe;
color: #1d4ed8;
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
text-align: center;
}
.member-title {
font-size: 16px;
font-weight: 600;
color: #1f2937;
}
.policy-link span:first-child {
font-size: 14px;
font-weight: 500;
color: #333;
}
/* 操作按钮 */
.action-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.action-btn {
padding: 14px 12px;
border: none;
border-radius: 12px;
font-size: 14px;
font-weight: 600;
text-align: center;
line-height: 1.2;
transition: all 0.2s;
width: 100%;
}
.action-btn:active {
transform: scale(0.98);
}
.exchange-btn {
background: linear-gradient(135deg, #f1eca6 2.82%, #ffd22f 99.15%), #fff;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
color: white;
}
.transfer-btn {
background: linear-gradient(135deg, #a6aaf1 2.82%, #592fff 99.15%), #fff;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
color: white;
}
/* Platform Policy 按钮样式 */
.platform-policy-btn {
background: none;
border: none;
color: #8b5cf6;
font-size: 14px;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
transition: all 0.2s;
}
.platform-policy-btn:hover {
color: #7c3aed;
}
.platform-policy-btn .arrow {
font-size: 16px;
font-weight: bold;
color: #8b5cf6;
}
/* 通用箭头样式 */
.arrow {
font-size: 16px;
font-weight: bold;
color: #8b5cf6;
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
.help-btn {
width: 14px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 12px;
}
.help-btn {
width: 16px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
.help-btn {
width: 28px;
}
}
/* RTL支持 */
[dir='rtl'] .avatar {
margin-right: 0;
margin-left: 12px;
}
[dir='rtl'] .user-details {
text-align: right;
}
[dir='rtl'] .notification-btn {
margin-left: 0;
margin-right: 12px;
}
[dir='rtl'] .help-btn {
/* transform: scaleX(-1); */
}
[dir='rtl'] .arrow {
transform: scaleX(-1);
}
[dir='rtl'] .card-link .arrow {
transform: scaleX(-1);
}
[dir='rtl'] .detail-row {
direction: rtl;
}
</style>