671 lines
20 KiB
Vue
671 lines
20 KiB
Vue
<script lang="ts" setup>
|
||
import {
|
||
computed,
|
||
reactive,
|
||
ref,
|
||
watch,
|
||
} from 'vue';
|
||
|
||
import { Page } from '@vben/common-ui';
|
||
import { useAccessStore } from '@vben/stores';
|
||
|
||
import { getCountryAlls } from '#/api/legacy/system';
|
||
import {
|
||
confirmManualSalary,
|
||
pageManualSalary,
|
||
} from '#/api/legacy/operate';
|
||
import AccountInput from '#/components/account-input.vue';
|
||
import AdminConfigTable from '#/views/_shared/admin-config-table.vue';
|
||
import { getAllowedSysOrigins } from '#/views/system/shared';
|
||
|
||
import {
|
||
Button,
|
||
Card,
|
||
Modal,
|
||
Select,
|
||
Space,
|
||
Table,
|
||
Tag,
|
||
message,
|
||
} from 'antdv-next';
|
||
|
||
import UserProfileLink from './components/user-profile-link.vue';
|
||
|
||
defineOptions({ name: 'OperateManualSalaryPayment' });
|
||
|
||
type SalarySortKey =
|
||
| 'currentSalaryBalance'
|
||
| 'payableSalary'
|
||
| 'totalIssuedSalary';
|
||
type SalarySortOrder = '' | 'ascend' | 'descend';
|
||
|
||
const accessStore = useAccessStore();
|
||
const sysOriginOptions = computed(() => {
|
||
const options = getAllowedSysOrigins(accessStore.accessCodes || []);
|
||
return options.length > 0 ? options : getAllowedSysOrigins([]);
|
||
});
|
||
|
||
const loading = ref(false);
|
||
const paying = ref(false);
|
||
const settlingUserId = ref('');
|
||
const total = ref(0);
|
||
const list = ref<Array<Record<string, any>>>([]);
|
||
const countries = ref<Array<Record<string, any>>>([]);
|
||
const countryKeyword = ref('');
|
||
const resultOpen = ref(false);
|
||
const resultRows = ref<Array<Record<string, any>>>([]);
|
||
const selectedUserIds = ref<string[]>([]);
|
||
const salarySortKey = ref<'' | SalarySortKey>('');
|
||
const salarySortOrder = ref<SalarySortOrder>('');
|
||
|
||
const query = reactive({
|
||
countryCode: '',
|
||
cursor: 1,
|
||
limit: 20,
|
||
sortField: '',
|
||
sortOrder: '' as SalarySortOrder,
|
||
sysOrigin: '',
|
||
userId: '',
|
||
});
|
||
|
||
const columns = [
|
||
{ dataIndex: 'userProfile', key: 'userProfile', title: '用户信息', width: 300 },
|
||
{ dataIndex: 'countryCode', key: 'countryCode', title: '国家', width: 90 },
|
||
{ dataIndex: 'lastSettlementTarget', key: 'lastSettlementTarget', title: '上次结算的积分', width: 150 },
|
||
{ dataIndex: 'currentTarget', key: 'currentTarget', title: '本次积分', width: 130 },
|
||
{ dataIndex: 'policyLevel', key: 'policyLevel', title: '本次积分档位', width: 130 },
|
||
{ dataIndex: 'expectedMemberSalary', key: 'expectedMemberSalary', title: '主播应发', width: 120 },
|
||
{ dataIndex: 'expectedAgentSalary', key: 'expectedAgentSalary', title: '代理应发', width: 120 },
|
||
{ dataIndex: 'expectedSalary', key: 'expectedSalary', title: '应发合计', width: 120 },
|
||
{ dataIndex: 'payableMemberSalary', key: 'payableMemberSalary', title: '主播差额', width: 120 },
|
||
{ dataIndex: 'payableAgentSalary', key: 'payableAgentSalary', title: '代理差额', width: 120 },
|
||
{ dataIndex: 'payableSalary', key: 'payableSalary', title: '合计差额', width: 140 },
|
||
{ dataIndex: 'memberIssuedSalary', key: 'memberIssuedSalary', title: '主播实收', width: 140 },
|
||
{ dataIndex: 'agentIssuedSalary', key: 'agentIssuedSalary', title: '代理实收', width: 140 },
|
||
{ dataIndex: 'totalIssuedSalary', key: 'totalIssuedSalary', title: '总发工资', width: 140 },
|
||
{ dataIndex: 'currentSalaryBalance', key: 'currentSalaryBalance', title: '当前工资', width: 140 },
|
||
{ dataIndex: 'action', fixed: 'right', key: 'action', title: '操作', width: 110 },
|
||
];
|
||
|
||
const resultColumns = [
|
||
{ dataIndex: 'userProfile', key: 'userProfile', title: '用户信息', width: 280 },
|
||
{ dataIndex: 'countryCode', key: 'countryCode', title: '国家', width: 90 },
|
||
{ dataIndex: 'salaryChange', key: 'salaryChange', title: '工资变动', width: 180 },
|
||
{ dataIndex: 'issuedSalary', key: 'issuedSalary', title: '发放工资', width: 120 },
|
||
{ dataIndex: 'policyLevel', key: 'policyLevel', title: '档位', width: 90 },
|
||
{ dataIndex: 'currentTarget', key: 'currentTarget', title: '本次积分', width: 120 },
|
||
];
|
||
|
||
const salarySortableKeys = new Set<SalarySortKey>([
|
||
'payableSalary',
|
||
'totalIssuedSalary',
|
||
'currentSalaryBalance',
|
||
]);
|
||
|
||
const hasMore = computed(() => list.value.length < total.value);
|
||
|
||
const tableRows = computed(() =>
|
||
list.value.map((item) => ({
|
||
...item,
|
||
rowKey: getRowKey(item),
|
||
})),
|
||
);
|
||
|
||
const summaryText = computed(() => {
|
||
if (total.value <= 0) {
|
||
return list.value.length > 0 ? `已加载 ${list.value.length} 条` : '';
|
||
}
|
||
return `已加载 ${list.value.length}/${total.value} 条`;
|
||
});
|
||
|
||
const selectedUserCount = computed(() => selectedUserIds.value.length);
|
||
|
||
const confirmButtonText = computed(() =>
|
||
selectedUserCount.value > 0
|
||
? `确认发放(${selectedUserCount.value}人)`
|
||
: '确认发放',
|
||
);
|
||
|
||
const rowSelection = computed(() => ({
|
||
getCheckboxProps: (record: Record<string, any>) => ({
|
||
disabled: !record.userId,
|
||
}),
|
||
onChange: (keys: Array<number | string>) => {
|
||
selectedUserIds.value = keys.map(String).filter(Boolean);
|
||
},
|
||
preserveSelectedRowKeys: true,
|
||
selectedRowKeys: selectedUserIds.value,
|
||
}));
|
||
|
||
const filteredCountries = computed(() => {
|
||
const keyword = countryKeyword.value.trim().toLowerCase();
|
||
if (!keyword) {
|
||
return countries.value;
|
||
}
|
||
return countries.value.filter((item) =>
|
||
[
|
||
item.phonePrefix,
|
||
item.countryName,
|
||
item.aliasName,
|
||
item.alphaTwo,
|
||
item.alphaThree,
|
||
]
|
||
.filter(Boolean)
|
||
.join(' ')
|
||
.toLowerCase()
|
||
.includes(keyword),
|
||
);
|
||
});
|
||
|
||
watch(
|
||
sysOriginOptions,
|
||
(options) => {
|
||
if (!query.sysOrigin && options.length > 0) {
|
||
query.sysOrigin = String(options[0]?.value || '');
|
||
}
|
||
},
|
||
{ immediate: true },
|
||
);
|
||
|
||
watch(
|
||
[() => query.sysOrigin, () => query.countryCode, () => query.userId],
|
||
() => {
|
||
selectedUserIds.value = [];
|
||
},
|
||
);
|
||
|
||
async function loadCountries() {
|
||
countries.value = (await getCountryAlls()) || [];
|
||
}
|
||
|
||
async function loadData(reset = false, append = false) {
|
||
if (!query.sysOrigin) {
|
||
return;
|
||
}
|
||
if (!query.countryCode) {
|
||
message.warning('请选择国家');
|
||
return;
|
||
}
|
||
if (reset) {
|
||
query.cursor = 1;
|
||
list.value = [];
|
||
total.value = 0;
|
||
selectedUserIds.value = [];
|
||
}
|
||
loading.value = true;
|
||
try {
|
||
const result = await pageManualSalary({ ...query });
|
||
const records = result.records || [];
|
||
list.value = append ? [...list.value, ...records] : records;
|
||
total.value = Number(result.total || 0);
|
||
sortLoadedRows();
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
async function loadNextPage() {
|
||
if (loading.value || !hasMore.value) {
|
||
return;
|
||
}
|
||
const previousCursor = query.cursor;
|
||
query.cursor = previousCursor + 1;
|
||
try {
|
||
await loadData(false, true);
|
||
} catch (error) {
|
||
query.cursor = previousCursor;
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
function formatMoney(value?: number | string) {
|
||
const amount = Number(value || 0);
|
||
if (Number.isNaN(amount)) {
|
||
return '$0.00';
|
||
}
|
||
return `$${amount.toFixed(2)}`;
|
||
}
|
||
|
||
function shouldShowAgentSalary(record: Record<string, any>) {
|
||
if (record.agentMember !== undefined && record.agentMember !== null) {
|
||
return record.agentMember === true;
|
||
}
|
||
return (
|
||
!!record.userId &&
|
||
!!record.teamOwnId &&
|
||
String(record.userId) === String(record.teamOwnId)
|
||
);
|
||
}
|
||
|
||
function formatAgentMoney(record: Record<string, any>, key: string) {
|
||
return shouldShowAgentSalary(record) ? formatMoney(record[key]) : '-';
|
||
}
|
||
|
||
function formatInteger(value?: number | string) {
|
||
if (value === undefined || value === null || value === '') {
|
||
return '-';
|
||
}
|
||
return Number(value).toLocaleString('en-US');
|
||
}
|
||
|
||
function countryLabel(code?: string) {
|
||
const country = countries.value.find((item) => item.alphaTwo === code);
|
||
if (!country) {
|
||
return code || '-';
|
||
}
|
||
return `${country.phonePrefix || ''} ${country.countryName || country.aliasName || code}`;
|
||
}
|
||
|
||
function getRowKey(record: Record<string, any>) {
|
||
return String(record.id || record.userProfile?.account || record.userId || '');
|
||
}
|
||
|
||
function getPayUserIdentifier(record: Record<string, any>) {
|
||
const account = record.userProfile?.account;
|
||
if (account && query.sysOrigin) {
|
||
return `*type:USER,sysOrigin:${query.sysOrigin},accountType:SHORT,content:${account}*`;
|
||
}
|
||
return String(record.userId || '');
|
||
}
|
||
|
||
function getSalarySortValue(
|
||
record: Record<string, any>,
|
||
key: SalarySortKey,
|
||
) {
|
||
const value = Number(record?.[key] || 0);
|
||
return Number.isFinite(value) ? value : 0;
|
||
}
|
||
|
||
function isSalarySortableColumn(key?: number | string) {
|
||
return salarySortableKeys.has(String(key || '') as SalarySortKey);
|
||
}
|
||
|
||
function salarySortIndicator(key?: number | string) {
|
||
if (salarySortKey.value !== String(key || '') || !salarySortOrder.value) {
|
||
return '排序';
|
||
}
|
||
return salarySortOrder.value === 'descend' ? '降序' : '升序';
|
||
}
|
||
|
||
function sortLoadedRows() {
|
||
if (!salarySortKey.value || !salarySortOrder.value) {
|
||
return;
|
||
}
|
||
const sortKey = salarySortKey.value;
|
||
const direction = salarySortOrder.value === 'ascend' ? 1 : -1;
|
||
list.value = [...list.value].sort((left, right) => {
|
||
const diff =
|
||
getSalarySortValue(left, sortKey) - getSalarySortValue(right, sortKey);
|
||
if (diff !== 0) {
|
||
return diff * direction;
|
||
}
|
||
return getRowKey(left).localeCompare(getRowKey(right));
|
||
});
|
||
}
|
||
|
||
function toggleSalarySort(key?: number | string) {
|
||
if (!isSalarySortableColumn(key)) {
|
||
return;
|
||
}
|
||
const nextKey = String(key) as SalarySortKey;
|
||
if (salarySortKey.value !== nextKey) {
|
||
salarySortKey.value = nextKey;
|
||
salarySortOrder.value = 'descend';
|
||
} else if (salarySortOrder.value === 'descend') {
|
||
salarySortOrder.value = 'ascend';
|
||
} else if (salarySortOrder.value === 'ascend') {
|
||
salarySortKey.value = '';
|
||
salarySortOrder.value = '';
|
||
} else {
|
||
salarySortOrder.value = 'descend';
|
||
}
|
||
query.sortField = salarySortKey.value;
|
||
query.sortOrder = salarySortOrder.value;
|
||
void loadData(true);
|
||
}
|
||
|
||
async function submitManualSalary(userIds?: string[]) {
|
||
const hasSelectedUsers = !!userIds?.length;
|
||
resultRows.value = await confirmManualSalary({
|
||
countryCode: query.countryCode,
|
||
sysOrigin: query.sysOrigin,
|
||
...(hasSelectedUsers ? { userIds } : {}),
|
||
});
|
||
resultOpen.value = true;
|
||
selectedUserIds.value = [];
|
||
await loadData(true);
|
||
}
|
||
|
||
function confirmPay() {
|
||
if (!query.countryCode) {
|
||
message.warning('请选择国家');
|
||
return;
|
||
}
|
||
|
||
const selectedKeys = new Set(selectedUserIds.value);
|
||
const userIds = tableRows.value
|
||
.filter((record) => selectedKeys.has(record.rowKey))
|
||
.map(getPayUserIdentifier)
|
||
.filter(Boolean);
|
||
const hasSelectedUsers = userIds.length > 0;
|
||
|
||
Modal.confirm({
|
||
content: hasSelectedUsers
|
||
? '本次只发放已勾选的用户。'
|
||
: '未勾选用户,本次将发放当前筛选国家的所有可发工资用户。',
|
||
title: hasSelectedUsers
|
||
? `确认发放已选择的 ${userIds.length} 人当前账期工资?`
|
||
: `确认发放 ${countryLabel(query.countryCode)} 当前账期工资?`,
|
||
async onOk() {
|
||
paying.value = true;
|
||
try {
|
||
await submitManualSalary(hasSelectedUsers ? userIds : undefined);
|
||
message.success('发放成功');
|
||
} finally {
|
||
paying.value = false;
|
||
}
|
||
},
|
||
});
|
||
}
|
||
|
||
function settleUser(record: Record<string, any>) {
|
||
if (!query.countryCode) {
|
||
message.warning('请选择国家');
|
||
return;
|
||
}
|
||
const userId = getPayUserIdentifier(record);
|
||
if (!userId) {
|
||
message.warning('用户ID为空');
|
||
return;
|
||
}
|
||
const payableSalary = Number(record.payableSalary || 0);
|
||
Modal.confirm({
|
||
content: payableSalary < 0
|
||
? '该用户应发小于实收,本次发放0并置为已结算,不会对用户扣款。'
|
||
: '本次只结算当前这一行用户的工资。',
|
||
title: `确认结算用户 ${record.userProfile?.account || userId} 的当前账期工资?`,
|
||
async onOk() {
|
||
settlingUserId.value = userId;
|
||
try {
|
||
await submitManualSalary([userId]);
|
||
message.success('结算成功');
|
||
} finally {
|
||
settlingUserId.value = '';
|
||
}
|
||
},
|
||
});
|
||
}
|
||
|
||
void loadCountries();
|
||
</script>
|
||
|
||
<template>
|
||
<Page
|
||
auto-content-height
|
||
content-class="manual-salary-page-content"
|
||
title="工资发放"
|
||
>
|
||
<div class="manual-salary-page">
|
||
<Card class="manual-salary-filter-card">
|
||
<Space wrap>
|
||
<SysOriginSelect
|
||
v-model:value="query.sysOrigin"
|
||
:options="sysOriginOptions"
|
||
style="width: 140px"
|
||
/>
|
||
<Select
|
||
v-model:value="query.countryCode"
|
||
allow-clear
|
||
show-search
|
||
:filter-option="false"
|
||
option-label-prop="label"
|
||
placeholder="国家"
|
||
style="width: 240px"
|
||
:options="filteredCountries.map((item) => ({
|
||
label: `${item.phonePrefix || ''} ${item.countryName || item.aliasName || ''}`,
|
||
value: item.alphaTwo as any,
|
||
}))"
|
||
@change="loadData(true)"
|
||
@search="countryKeyword = $event"
|
||
/>
|
||
<AccountInput
|
||
v-model:value="query.userId"
|
||
:sys-origin="query.sysOrigin"
|
||
placeholder="用户ID"
|
||
style="width: 260px"
|
||
/>
|
||
<Button :loading="loading" type="primary" @click="loadData(true)">
|
||
搜索
|
||
</Button>
|
||
<Button
|
||
danger
|
||
:disabled="!query.countryCode"
|
||
:loading="paying"
|
||
@click="confirmPay"
|
||
>
|
||
{{ confirmButtonText }}
|
||
</Button>
|
||
</Space>
|
||
</Card>
|
||
|
||
<AdminConfigTable
|
||
auto-height
|
||
:columns="columns"
|
||
:current="query.cursor"
|
||
:data-source="tableRows"
|
||
:has-more="hasMore"
|
||
infinite
|
||
:loading="loading"
|
||
:page-size="query.limit"
|
||
row-key="rowKey"
|
||
:row-selection="rowSelection"
|
||
:scroll-x="2340"
|
||
:show-pager="false"
|
||
:summary-text="summaryText"
|
||
:total="total"
|
||
@load-more="loadNextPage"
|
||
>
|
||
<template #headerCell="{ column }">
|
||
<button
|
||
v-if="isSalarySortableColumn(column.key)"
|
||
class="salary-sort-header"
|
||
:class="{ 'salary-sort-header--active': salarySortKey === column.key }"
|
||
type="button"
|
||
@click="toggleSalarySort(column.key)"
|
||
>
|
||
<span>{{ column.title }}</span>
|
||
<span class="salary-sort-state">
|
||
{{ salarySortIndicator(column.key) }}
|
||
</span>
|
||
</button>
|
||
<template v-else>
|
||
{{ column.title }}
|
||
</template>
|
||
</template>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'userProfile'">
|
||
<UserProfileLink :profile="record.userProfile" />
|
||
</template>
|
||
<template v-else-if="column.key === 'countryCode'">
|
||
{{ record.countryCode || '-' }}
|
||
</template>
|
||
<template v-else-if="column.key === 'lastSettlementTarget'">
|
||
{{ formatInteger(record.lastSettlementTarget) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'currentTarget'">
|
||
{{ formatInteger(record.currentTarget) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'policyLevel'">
|
||
<Tag v-if="record.policyLevel" color="blue">
|
||
{{ record.policyLevel }}
|
||
</Tag>
|
||
<span v-else>-</span>
|
||
</template>
|
||
<template v-else-if="column.key === 'expectedSalary'">
|
||
{{ formatMoney(record.expectedSalary) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'expectedMemberSalary'">
|
||
{{ formatMoney(record.expectedMemberSalary) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'expectedAgentSalary'">
|
||
{{ formatAgentMoney(record, 'expectedAgentSalary') }}
|
||
</template>
|
||
<template v-else-if="column.key === 'payableMemberSalary'">
|
||
<span
|
||
:class="{ 'payable-salary-negative': Number(record.payableMemberSalary || 0) < 0 }"
|
||
>
|
||
{{ formatMoney(record.payableMemberSalary) }}
|
||
</span>
|
||
</template>
|
||
<template v-else-if="column.key === 'payableAgentSalary'">
|
||
<span
|
||
:class="{ 'payable-salary-negative': Number(record.payableAgentSalary || 0) < 0 }"
|
||
>
|
||
{{ formatAgentMoney(record, 'payableAgentSalary') }}
|
||
</span>
|
||
</template>
|
||
<template v-else-if="column.key === 'payableSalary'">
|
||
<Space size="small">
|
||
<span
|
||
:class="{ 'payable-salary-negative': Number(record.payableSalary || 0) < 0 }"
|
||
>
|
||
{{ formatMoney(record.payableSalary) }}
|
||
</span>
|
||
<Tag v-if="record.paid" color="green">已结算</Tag>
|
||
</Space>
|
||
</template>
|
||
<template v-else-if="column.key === 'memberIssuedSalary'">
|
||
<span>{{ formatMoney(record.memberIssuedSalary) }}</span>
|
||
<span
|
||
v-if="Number(record.memberOverIssuedSalary || 0) > 0"
|
||
class="over-issued-salary"
|
||
>
|
||
({{ formatMoney(record.memberOverIssuedSalary) }})
|
||
</span>
|
||
</template>
|
||
<template v-else-if="column.key === 'agentIssuedSalary'">
|
||
<span>{{ formatAgentMoney(record, 'agentIssuedSalary') }}</span>
|
||
<span
|
||
v-if="shouldShowAgentSalary(record) && Number(record.agentOverIssuedSalary || 0) > 0"
|
||
class="over-issued-salary"
|
||
>
|
||
({{ formatMoney(record.agentOverIssuedSalary) }})
|
||
</span>
|
||
</template>
|
||
<template v-else-if="column.key === 'totalIssuedSalary'">
|
||
<span>{{ formatMoney(record.totalIssuedSalary) }}</span>
|
||
<span
|
||
v-if="Number(record.overIssuedSalary || 0) > 0"
|
||
class="over-issued-salary"
|
||
>
|
||
({{ formatMoney(record.overIssuedSalary) }})
|
||
</span>
|
||
</template>
|
||
<template v-else-if="column.key === 'currentSalaryBalance'">
|
||
{{ formatMoney(record.currentSalaryBalance) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'action'">
|
||
<Button
|
||
:disabled="!record.userId || record.paid"
|
||
:loading="settlingUserId === String(record.userId || '')"
|
||
size="small"
|
||
type="primary"
|
||
@click="settleUser(record)"
|
||
>
|
||
结算
|
||
</Button>
|
||
</template>
|
||
</template>
|
||
</AdminConfigTable>
|
||
</div>
|
||
|
||
<Modal
|
||
v-model:open="resultOpen"
|
||
:footer="null"
|
||
title="发放结果"
|
||
width="980px"
|
||
>
|
||
<Table
|
||
:columns="resultColumns"
|
||
:data-source="resultRows"
|
||
:pagination="false"
|
||
row-key="id"
|
||
size="small"
|
||
:scroll="{ x: 900, y: 520 }"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'userProfile'">
|
||
<UserProfileLink :profile="record.userProfile" />
|
||
</template>
|
||
<template v-else-if="column.key === 'salaryChange'">
|
||
{{ formatMoney(record.beforeSalaryBalance) }} -> {{ formatMoney(record.afterSalaryBalance) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'issuedSalary'">
|
||
{{ formatMoney(record.issuedSalary) }}
|
||
</template>
|
||
<template v-else-if="column.key === 'policyLevel'">
|
||
<Tag color="blue">{{ record.policyLevel || '-' }}</Tag>
|
||
</template>
|
||
<template v-else-if="column.key === 'currentTarget'">
|
||
{{ formatInteger(record.currentTarget) }}
|
||
</template>
|
||
</template>
|
||
</Table>
|
||
</Modal>
|
||
</Page>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.manual-salary-page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
height: 100%;
|
||
min-height: 0;
|
||
}
|
||
|
||
.manual-salary-filter-card {
|
||
flex: 0 0 auto;
|
||
}
|
||
|
||
.salary-sort-header {
|
||
align-items: center;
|
||
background: transparent;
|
||
border: 0;
|
||
color: inherit;
|
||
cursor: pointer;
|
||
display: inline-flex;
|
||
font: inherit;
|
||
gap: 6px;
|
||
max-width: 100%;
|
||
padding: 0;
|
||
text-align: left;
|
||
}
|
||
|
||
.salary-sort-header:hover,
|
||
.salary-sort-header--active {
|
||
color: rgb(22 119 255);
|
||
}
|
||
|
||
.salary-sort-state {
|
||
color: rgb(102 112 133);
|
||
flex: 0 0 auto;
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.salary-sort-header--active .salary-sort-state {
|
||
color: rgb(22 119 255);
|
||
}
|
||
|
||
.over-issued-salary {
|
||
color: rgb(217 45 32);
|
||
margin-left: 4px;
|
||
}
|
||
|
||
.payable-salary-negative {
|
||
color: rgb(217 45 32);
|
||
font-weight: 600;
|
||
}
|
||
</style>
|