Compare commits
2 Commits
master
...
lm/feat/da
| Author | SHA1 | Date | |
|---|---|---|---|
| 2cc61a524d | |||
| 5883d98f51 |
@ -1,17 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
// postcss-pxtorem 插件已禁用
|
||||
// 如需响应式设计,可重新启用
|
||||
// 'postcss-pxtorem': {
|
||||
// rootValue: 16,
|
||||
// unitPrecision: 5,
|
||||
// propList: ['*'],
|
||||
// selectorBlackList: [],
|
||||
// replace: true,
|
||||
// mediaQuery: false,
|
||||
// minPixelValue: 0,
|
||||
// exclude: /node_modules/i
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,65 +535,3 @@ export const subString = (str: string, start: number, end: number) => {
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML转义 - 防止XSS攻击
|
||||
* @param str 需要转义的HTML字符串
|
||||
* @returns 转义后的字符串
|
||||
*/
|
||||
export const escapeHtml = (str: string): string => {
|
||||
if (!str) return ''
|
||||
const htmlEscapes: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
'`': '`',
|
||||
'=': '='
|
||||
}
|
||||
return str.replace(/[&<>"'`=/]/g, (char) => htmlEscapes[char])
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全的HTML显示 - 仅允许安全的HTML标签和属性
|
||||
* @param html 需要处理的HTML字符串
|
||||
* @returns 处理后的安全HTML字符串
|
||||
*/
|
||||
export const sanitizeHtml = (html: string): string => {
|
||||
if (!html) return ''
|
||||
|
||||
// 允许的标签(只保留文本格式化的基本标签)
|
||||
const allowedTags = ['p', 'br', 'b', 'i', 'u', 'strong', 'em', 'span', 'div', 'ul', 'li', 'ol']
|
||||
|
||||
// 允许的标签及其属性
|
||||
const allowedAttributes: Record<string, string[]> = {
|
||||
span: ['style'],
|
||||
div: ['style']
|
||||
}
|
||||
|
||||
// 移除所有script标签和事件属性
|
||||
let sanitized = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
||||
sanitized = sanitized.replace(/\s*on\w+\s*=\s*(['"])[^'"]*\1/gi, '')
|
||||
sanitized = sanitized.replace(/\s*on\w+\s*=\s*[^\s>]+/gi, '')
|
||||
|
||||
// 只保留允许的标签
|
||||
allowedTags.forEach((tag) => {
|
||||
// 移除不允许的标签,保留内容
|
||||
const regex = new RegExp(`<${tag}[^>]*>|</${tag}>`, 'gi')
|
||||
sanitized = sanitized.replace(regex, (match) => match.toLowerCase())
|
||||
})
|
||||
|
||||
// 移除所有其他标签
|
||||
sanitized = sanitized.replace(/<[^>]+>/g, (match) => {
|
||||
// 检查是否是允许的标签
|
||||
const tagMatch = match.match(/^<([a-z]+)/i)
|
||||
if (tagMatch && allowedTags.includes(tagMatch[1].toLowerCase())) {
|
||||
return match // 保留允许的标签
|
||||
}
|
||||
return '' // 移除不允许的标签
|
||||
})
|
||||
|
||||
return sanitized
|
||||
}
|
||||
|
||||
@ -198,47 +198,57 @@ const basicInfo = ref({
|
||||
const interviewRecords = ref<{ date: string; content: string }[]>([])
|
||||
|
||||
// 计分考核数据
|
||||
const scoreRecords = ref<{
|
||||
date: string
|
||||
score: string
|
||||
scoreType: 'positive' | 'negative'
|
||||
finalScore: number
|
||||
level: 'excellent' | 'good' | 'poor'
|
||||
levelText: string
|
||||
}[]>([])
|
||||
const scoreRecords = ref<
|
||||
{
|
||||
date: string
|
||||
score: string
|
||||
scoreType: 'positive' | 'negative'
|
||||
finalScore: number
|
||||
level: 'excellent' | 'good' | 'poor'
|
||||
levelText: string
|
||||
}[]
|
||||
>([])
|
||||
|
||||
// 消费记录数据
|
||||
const consumptionRecords = ref<{
|
||||
date: string
|
||||
name: string
|
||||
nameColor: string
|
||||
category: string
|
||||
amount: number
|
||||
}[]>([])
|
||||
const consumptionRecords = ref<
|
||||
{
|
||||
date: string
|
||||
name: string
|
||||
nameColor: string
|
||||
category: string
|
||||
amount: number
|
||||
}[]
|
||||
>([])
|
||||
|
||||
// 汇款记录数据
|
||||
const remittanceRecords = ref<{
|
||||
date: string
|
||||
name: string
|
||||
nameColor: string
|
||||
category: string
|
||||
amount: number
|
||||
}[]>([])
|
||||
const remittanceRecords = ref<
|
||||
{
|
||||
date: string
|
||||
name: string
|
||||
nameColor: string
|
||||
category: string
|
||||
amount: number
|
||||
}[]
|
||||
>([])
|
||||
|
||||
// 关系人数据
|
||||
const relationships = ref<{
|
||||
name: string
|
||||
relate: string
|
||||
color: string
|
||||
}[]>([])
|
||||
const relationships = ref<
|
||||
{
|
||||
name: string
|
||||
relate: string
|
||||
color: string
|
||||
}[]
|
||||
>([])
|
||||
|
||||
// 奖惩记录数据
|
||||
const rewardsPunishments = ref<{
|
||||
date: string
|
||||
type: string
|
||||
typeText: string
|
||||
content: string
|
||||
}[]>([])
|
||||
const rewardsPunishments = ref<
|
||||
{
|
||||
date: string
|
||||
type: string
|
||||
typeText: string
|
||||
content: string
|
||||
}[]
|
||||
>([])
|
||||
|
||||
// 当前时间
|
||||
const currentTime = ref('')
|
||||
@ -431,23 +441,23 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.prison-name {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
position: fixed;
|
||||
top: 18px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: white;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
font-size: 28px;
|
||||
font-size: 26px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.current-time {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
right: 32px;
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
right: 50px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
z-index: 1000;
|
||||
@ -510,15 +520,15 @@ onUnmounted(() => {
|
||||
background: #2d3d5f;
|
||||
border: 1px solid rgba(56, 102, 141, 0.5);
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-left: 18px;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-card-item-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 12px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.icon-location {
|
||||
background: url('@/assets/imgs/dashboard/icon-location.svg') no-repeat center center;
|
||||
@ -537,7 +547,7 @@ onUnmounted(() => {
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.list-card-item-value {
|
||||
font-size: 18px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
@ -563,8 +573,8 @@ onUnmounted(() => {
|
||||
|
||||
// 信息卡片通用样式
|
||||
.info-card-item {
|
||||
border-radius: 4px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 2px;
|
||||
padding: 18px 20px;
|
||||
box-shadow: inset 0 0 15px 0 #2b4183;
|
||||
border: 1px solid #2b4183;
|
||||
display: flex;
|
||||
@ -582,17 +592,17 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.card-number {
|
||||
font-size: 20px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 10px;
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@ -637,7 +647,7 @@ onUnmounted(() => {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.dashboard-content-bottom-right-title {
|
||||
font-size: 18px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
margin-bottom: 12px;
|
||||
|
||||
@ -155,7 +155,7 @@ watch(
|
||||
|
||||
.consumption-records-title {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
@ -186,7 +186,7 @@ watch(
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
@ -218,12 +218,12 @@ watch(
|
||||
}
|
||||
|
||||
.record-date {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.record-name {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
|
||||
&.name-purple {
|
||||
@ -252,12 +252,12 @@ watch(
|
||||
}
|
||||
|
||||
.record-category {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.record-amount {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
text-align: right;
|
||||
@ -268,8 +268,8 @@ watch(
|
||||
}
|
||||
.relationship-item {
|
||||
background: #422b1f;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
@ -296,8 +296,8 @@ watch(
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
svg {
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
width: 12px;
|
||||
height: 13px;
|
||||
}
|
||||
&.icon-orange {
|
||||
color: #ffa500;
|
||||
@ -314,11 +314,9 @@ watch(
|
||||
}
|
||||
|
||||
.relationship-name {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
font-size: 11px;
|
||||
}
|
||||
.relationship-relate {
|
||||
font-size: 12px;
|
||||
opacity: 0.8;
|
||||
font-size: 11px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -168,8 +168,8 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
margin-right: 6px;
|
||||
font-size: 14px;
|
||||
margin-right: 2px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -193,8 +193,8 @@ const props = withDefaults(
|
||||
padding: 6px 10px;
|
||||
background: #3f6973;
|
||||
border: 1px solid rgba(56, 102, 141, 0.5);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
border-radius: 2px;
|
||||
font-size: 9px;
|
||||
color: #d8f0ff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@ -206,7 +206,7 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.records-content-title {
|
||||
font-size: 14px;
|
||||
font-size: 10px;
|
||||
color: #d8f0ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -220,7 +220,7 @@ const props = withDefaults(
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
font-size: 10px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ const props = withDefaults(
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 2px;
|
||||
height: calc(100% + 6px);
|
||||
height: calc(100% + 14px);
|
||||
background: rgba(56, 102, 141, 0.5);
|
||||
}
|
||||
}
|
||||
@ -283,14 +283,14 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
.record-date {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.record-text {
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
color: #d8f0ff;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ watch(
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
@ -124,8 +124,8 @@ watch(
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
padding: 4px 6px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgba(56, 102, 141, 0.2);
|
||||
border-radius: 4px;
|
||||
@ -179,11 +179,11 @@ watch(
|
||||
// 时间线标记点
|
||||
.timeline-dot {
|
||||
position: absolute;
|
||||
left: -6px;
|
||||
left: -8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(13, 30, 50, 0.8);
|
||||
background: rgba(13, 30, 50, 0.8);
|
||||
@ -205,13 +205,12 @@ watch(
|
||||
flex: 1;
|
||||
background: rgba(56, 102, 141, 0.15);
|
||||
border: 1px solid rgba(56, 102, 141, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 8px 12px;
|
||||
margin-left: 8px;
|
||||
border-radius: 2px;
|
||||
padding: 6px 14px;
|
||||
}
|
||||
|
||||
.card-type {
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
@ -226,7 +225,7 @@ watch(
|
||||
}
|
||||
|
||||
.card-description {
|
||||
font-size: 12px;
|
||||
font-size: 8px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@ -101,8 +101,8 @@ watch(
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
margin-right: 6px;
|
||||
font-size: 14px;
|
||||
margin-right: 2px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
@ -132,8 +132,8 @@ watch(
|
||||
}
|
||||
|
||||
.header-cell {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -144,7 +144,7 @@ watch(
|
||||
background-size: 100% 100%;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 4px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
// 表格主体
|
||||
@ -169,11 +169,11 @@ watch(
|
||||
background-size: 100% 100%;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 4px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.row-cell {
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user