提交 4a7526c1 authored 作者: 朱政's avatar 朱政

feat:风险信号样式调整

上级 5ba7a5e0
流水线 #616 已通过 于阶段
in 1 分 49 秒
...@@ -20,24 +20,51 @@ const route = useRoute(); ...@@ -20,24 +20,51 @@ const route = useRoute();
const type = ref(route.query.type || 1); const type = ref(route.query.type || 1);
const decodeMaybeBase64 = (raw) => { const decodeMaybeBase64 = (raw) => {
if (raw == null) return null; if (raw == null) return null;
const s0 = String(raw).trim(); let s0 = String(raw).trim();
if (!s0) return null; if (!s0) return null;
// 兼容 URL 里被 encodeURIComponent 的 base64(例如 OTg%3D)
if (s0.includes("%")) {
try {
const decodedOnce = decodeURIComponent(s0);
if (decodedOnce) s0 = String(decodedOnce).trim();
} catch (_) { }
}
// 明文 personId(如 Y000064)保持原样,避免误解码 // 明文 personId(如 Y000064)保持原样,避免误解码
if (/^[A-Za-z]\d{6,}$/.test(s0) || /^Y\d+/i.test(s0)) { if (/^[A-Za-z]\d{6,}$/.test(s0) || /^Y\d+/i.test(s0)) {
return s0; return s0;
} }
if (s0.length >= 12 && /^[A-Za-z0-9+/_-]+={0,2}$/.test(s0)) { // 只在“可逆校验通过”时才把它当作 base64(encodeURIComponent(x))
if (!/^[A-Za-z0-9+/_-]+={0,2}$/.test(s0)) return s0;
const encodeBase64Param = (val) => {
const s = String(val ?? "").trim();
if (!s) return "";
try { try {
const normalized = s0.replace(/-/g, "+").replace(/_/g, "/"); return btoa(encodeURIComponent(s));
const padded = normalized + "===".slice((normalized.length + 3) % 4); } catch (_) {
const decoded = atob(padded); return s;
}
};
const normalizeBase64 = (s) => {
const normalized = String(s ?? "").replace(/-/g, "+").replace(/_/g, "/");
return normalized + "===".slice((normalized.length + 3) % 4);
};
try {
const padded = normalizeBase64(s0);
const decoded = atob(padded);
const decodedStr = (() => {
try { try {
return decodeURIComponent(decoded); return decodeURIComponent(decoded);
} catch (_) { } catch (_) {
return decoded; return decoded;
} }
} catch (_) { } })();
} const reEncoded = encodeBase64Param(decodedStr);
if (reEncoded && normalizeBase64(reEncoded) === padded) {
return decodedStr;
}
} catch (_) { }
return s0; return s0;
}; };
const personId = ref(decodeMaybeBase64(route.query.personId) || "Y000064"); const personId = ref(decodeMaybeBase64(route.query.personId) || "Y000064");
......
...@@ -235,15 +235,35 @@ const handleClickOnEntity = (item) => { ...@@ -235,15 +235,35 @@ const handleClickOnEntity = (item) => {
} }
})(); })();
if (!encodedPersonId) return; if (!encodedPersonId) return;
const url = `http://localhost:3000/characterPage?type=2&personId=${encodeURIComponent(encodedPersonId)}`; const { href } = router.resolve({
window.open(url, "_blank"); path: "/characterPage",
query: {
type: 2,
personId: encodedPersonId
}
});
window.open(href, "_blank");
return; return;
} }
// 默认按公司/机构跳转(含 ENTITYTYPE === 'O' 或字段缺失) // 默认按公司/机构跳转(含 ENTITYTYPE === 'O' 或字段缺失)
const companyId = item?.ENTITYID || item?.id; const companyId = item?.ENTITYID || item?.id;
if (!companyId) return; if (!companyId) return;
const path = `/companyPages/${companyId}`; const encodedInstitutionId = (() => {
const { href } = router.resolve({ path }); const s = String(companyId ?? "").trim();
if (!s) return "";
try {
return btoa(encodeURIComponent(s));
} catch (_) {
return s;
}
})();
if (!encodedInstitutionId) return;
const { href } = router.resolve({
path: "/institution",
query: {
id: encodedInstitutionId
}
});
window.open(href, "_blank"); window.open(href, "_blank");
}; };
......
...@@ -48,6 +48,52 @@ import { ElMessage } from "element-plus"; ...@@ -48,6 +48,52 @@ import { ElMessage } from "element-plus";
const route = useRoute(); const route = useRoute();
const decodeMaybeBase64 = (raw) => {
if (raw == null) return "";
let s0 = String(raw).trim();
if (!s0) return "";
if (s0.includes("%")) {
try {
const decodedOnce = decodeURIComponent(s0);
if (decodedOnce) s0 = String(decodedOnce).trim();
} catch (_) { }
}
// 非 base64 直接返回(机构 id 含字母数字,明文也要支持)
if (!/^[A-Za-z0-9+/_-]+={0,2}$/.test(s0)) return s0;
const encodeBase64Param = (val) => {
const s = String(val ?? "").trim();
if (!s) return "";
try {
return btoa(encodeURIComponent(s));
} catch (_) {
return s;
}
};
const normalizeBase64 = (s) => {
const normalized = String(s ?? "").replace(/-/g, "+").replace(/_/g, "/");
return normalized + "===".slice((normalized.length + 3) % 4);
};
try {
const padded = normalizeBase64(s0);
const decoded = atob(padded);
const decodedStr = (() => {
try {
return decodeURIComponent(decoded);
} catch (_) {
return decoded;
}
})();
const reEncoded = encodeBase64Param(decodedStr);
if (reEncoded && normalizeBase64(reEncoded) === padded) {
return decodedStr;
}
} catch (_) { }
return s0;
};
const institutionId = computed(() => decodeMaybeBase64(route.query.id));
const institutionInfo = ref({ const institutionInfo = ref({
name: "", name: "",
enName: "", enName: "",
...@@ -66,7 +112,7 @@ const showTagList = computed(() => { ...@@ -66,7 +112,7 @@ const showTagList = computed(() => {
const handleGetInfo = async () => { const handleGetInfo = async () => {
const params = { const params = {
id: route.query.id id: institutionId.value
}; };
try { try {
const res = await getGovOrgBasicInfo(params); const res = await getGovOrgBasicInfo(params);
......
...@@ -173,59 +173,43 @@ ...@@ -173,59 +173,43 @@
<div class="search-btn" @click="handleSearch"></div> <div class="search-btn" @click="handleSearch"></div>
</div> </div>
<div class="select-box"> <div class="select-box">
<el-select v-model="sortModel" class="resource-library-sort-select" placeholder="发布时间" <TimeSortSelectBox :sort-demension="1" @handlePxChange="handleTimeSortChange" />
style="width: 120px" :teleported="true" placement="bottom-start"
:popper-options="resourceLibrarySortPopperOptions" @change="handleSortChange">
<template #prefix>
<img v-if="sortValue === 1"
src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png"
class="resource-library-sort-prefix-img" alt="" @click.stop="toggleSortPrefix" />
<img v-else src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image up.png"
class="resource-library-sort-prefix-img" alt="" @click.stop="toggleSortPrefix" />
</template>
<el-option :key="'risk-sort-asc'" label="正序" :value="0" />
<el-option :key="'risk-sort-desc'" label="倒序" :value="1" />
</el-select>
</div> </div>
</div> </div>
</div> </div>
<template v-if="riskList && riskList.length"> <div v-if="riskList && riskList.length" class="right-main">
<div class="right-main"> <div class="itemlist itemlist--clickable" v-for="(val, idx) in riskList" :key="val.rowKey"
<div class="itemlist itemlist--clickable" v-for="(val, idx) in riskList" :key="val.rowKey" @click="handleOpenRiskDetail(val)">
@click="handleOpenRiskDetail(val)"> <div class="box-title">
<div class="box-title"> <div class="risktitle" v-html="highlightRiskText(val.title)" />
<div class="risktitle" v-html="highlightRiskText(val.title)" /> <div v-if="!isRiskLevelNoData(val.risktype)" class="risktype"
<div v-if="!isRiskLevelNoData(val.risktype)" class="risktype" :class="'risktype--' + getRiskListItemLevelKey(val.risktype)">
:class="'risktype--' + getRiskListItemLevelKey(val.risktype)"> <div class="icon" :class="'icon--' + getRiskListItemLevelKey(val.risktype)" />
<div class="icon" :class="'icon--' + getRiskListItemLevelKey(val.risktype)" /> <div class="text">{{ getRiskListItemLevelLabel(val.risktype) }}</div>
<div class="text">{{ getRiskListItemLevelLabel(val.risktype) }}</div>
</div>
</div>
<div class="box-source">
<img class="source-pic" :src="val.pic || DefaultIcon2" alt="" />
<div class="source-text">{{ formatRiskSourceLine(val) }}</div>
</div>
<div class="desc-box" v-html="highlightRiskText(val.dsc)" />
<div class="tag-box" v-if="val.tag.length">
<AreaTag v-for="(tag, index) in val.tag" :key="index" :tagName="tag">{{ tag }}</AreaTag>
</div> </div>
</div> </div>
</div> <div class="box-source">
<div class="right-footer"> <img class="source-pic" :src="val.pic || DefaultIcon2" alt="" />
<div class="footer-left"> <div class="source-text">{{ formatRiskSourceLine(val) }}</div>
{{ `共 ${formatThousands(totalNum)} 项调查` }}
</div> </div>
<div class="footer-right"> <div class="desc-box" v-html="highlightRiskText(val.dsc)" />
<el-pagination @current-change="handleCurrentChange" :pageSize="pageSize" :current-page="currentPage" <div class="tag-box" v-if="val.tag.length">
:total="totalNum" background layout="prev, pager, next" /> <AreaTag v-for="(tag, index) in val.tag" :key="index" :tagName="tag">{{ tag }}</AreaTag>
</div> </div>
</div> </div>
</template> </div>
<template v-else> <div v-else class="right-empty">
<div class="right-empty"> <el-empty class="right-el-empty" description="暂无数据" :image-size="100" />
<el-empty class="right-el-empty" description="暂无数据" :image-size="100" /> </div>
<div class="right-footer">
<div class="footer-left">
{{ `共 ${formatThousands(totalNum)} 项调查` }}
</div>
<div class="footer-right">
<el-pagination @current-change="handleCurrentChange" :pageSize="pageSize" :current-page="currentPage"
:total="totalNum" background layout="prev, pager, next" />
</div> </div>
</template> </div>
</div> </div>
</div> </div>
</div> </div>
...@@ -311,12 +295,14 @@ import riskSourceUpArrow from "./assets/images/up-arrow.png"; ...@@ -311,12 +295,14 @@ import riskSourceUpArrow from "./assets/images/up-arrow.png";
import DefaultIcon2 from "@/assets/icons/default-icon2.png"; import DefaultIcon2 from "@/assets/icons/default-icon2.png";
import { normalizeExclusiveAllOption } from "@/views/thinkTank/utils/resourceLibraryFilters"; import { normalizeExclusiveAllOption } from "@/views/thinkTank/utils/resourceLibraryFilters";
import TimeSortSelectBox from "@/components/base/TimeSortSelectBox/index.vue";
const riskTypeOptions = ref([]); const riskTypeOptions = ref([]);
const RISK_FILTER_ALL_TYPE = "全部类型"; const RISK_FILTER_ALL_TYPE = "全部类型";
const selectedRiskTypeModel = ref([RISK_FILTER_ALL_TYPE]); const selectedRiskTypeModel = ref([RISK_FILTER_ALL_TYPE]);
const handleRiskTypeGroupChange = (val) => { const handleRiskTypeGroupChange = (val) => {
selectedRiskTypeModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_TYPE); selectedRiskTypeModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_TYPE);
currentPage.value = 1;
handleGetPageQuery(); handleGetPageQuery();
}; };
...@@ -336,6 +322,7 @@ const timeSource = ref([ ...@@ -336,6 +322,7 @@ const timeSource = ref([
const selectedTimeModel = ref([Time_FILTER_ALL_SOURCE]); const selectedTimeModel = ref([Time_FILTER_ALL_SOURCE]);
const handleTimeGroupChange = (val) => { const handleTimeGroupChange = (val) => {
selectedTimeModel.value = normalizeExclusiveAllOption(val, Time_FILTER_ALL_SOURCE); selectedTimeModel.value = normalizeExclusiveAllOption(val, Time_FILTER_ALL_SOURCE);
currentPage.value = 1;
handleGetPageQuery(); handleGetPageQuery();
}; };
...@@ -351,6 +338,7 @@ const RISK_FILTER_ALL_SOURCE = "全部国家"; ...@@ -351,6 +338,7 @@ const RISK_FILTER_ALL_SOURCE = "全部国家";
const selectedRiskSourceModel = ref([RISK_FILTER_ALL_SOURCE]); const selectedRiskSourceModel = ref([RISK_FILTER_ALL_SOURCE]);
const handleRiskSourceGroupChange = (val) => { const handleRiskSourceGroupChange = (val) => {
selectedRiskSourceModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_SOURCE); selectedRiskSourceModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_SOURCE);
currentPage.value = 1;
handleGetPageQuery(); handleGetPageQuery();
}; };
...@@ -384,6 +372,7 @@ const RISK_FILTER_ALL_LEVEL = "全部等级"; ...@@ -384,6 +372,7 @@ const RISK_FILTER_ALL_LEVEL = "全部等级";
const selectedRiskDegreeModel = ref([RISK_FILTER_ALL_LEVEL]); const selectedRiskDegreeModel = ref([RISK_FILTER_ALL_LEVEL]);
const handleRiskDegreeGroupChange = (val) => { const handleRiskDegreeGroupChange = (val) => {
selectedRiskDegreeModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_LEVEL); selectedRiskDegreeModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_LEVEL);
currentPage.value = 1;
handleGetPageQuery(); handleGetPageQuery();
}; };
...@@ -410,6 +399,7 @@ const RISK_FILTER_ALL_AREA = "全部领域"; ...@@ -410,6 +399,7 @@ const RISK_FILTER_ALL_AREA = "全部领域";
const selectedAreaModel = ref([RISK_FILTER_ALL_AREA]); const selectedAreaModel = ref([RISK_FILTER_ALL_AREA]);
const handleAreaGroupChange = (val) => { const handleAreaGroupChange = (val) => {
selectedAreaModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_AREA); selectedAreaModel.value = normalizeExclusiveAllOption(val, RISK_FILTER_ALL_AREA);
currentPage.value = 1;
handleGetPageQuery(); handleGetPageQuery();
}; };
...@@ -710,26 +700,10 @@ const handleCleandarChart = async () => { ...@@ -710,26 +700,10 @@ const handleCleandarChart = async () => {
/** sort:0 正序;1 倒序;接口默认倒序=1 */ /** sort:0 正序;1 倒序;接口默认倒序=1 */
const sortValue = ref(1); const sortValue = ref(1);
/** el-select 展示用:默认 null => 显示 placeholder「发布时间」 */ const handleTimeSortChange = (val) => {
const sortModel = ref(null); // TimeSortSelectBox: 1=时间倒序,2=时间正序
sortValue.value = val === 2 ? 0 : 1;
const resourceLibrarySortPopperOptions = { currentPage.value = 1;
modifiers: [
{ name: "preventOverflow", options: { mainAxis: false, altAxis: false } },
{ name: "flip", enabled: false }
]
};
const toggleSortPrefix = () => {
sortValue.value = sortValue.value === 1 ? 0 : 1;
sortModel.value = sortValue.value;
handleSortChange();
};
const handleSortChange = () => {
if (sortModel.value === 0 || sortModel.value === 1) {
sortValue.value = sortModel.value;
}
handleGetPageQuery(); handleGetPageQuery();
}; };
...@@ -1308,9 +1282,7 @@ onMounted(async () => { ...@@ -1308,9 +1282,7 @@ onMounted(async () => {
} }
.select-box { .select-box {
width: 120px;
height: 32px;
box-sizing: border-box;
.resource-library-sort-select { .resource-library-sort-select {
:deep(.el-select__wrapper) { :deep(.el-select__wrapper) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论