更新代码
This commit is contained in:
@@ -120,6 +120,7 @@ import { User, SwitchButton, Sunny, Moon, Refresh, Bell, HomeFilled, Loading, Me
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { getMySiteReminders, readAllSiteReminders } from "@/api/sitereminder";
|
||||
import MessageDetailDialog from "./MessageDetailDialog.vue";
|
||||
import { formatTime } from "@/utils/datetime";
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@@ -181,12 +182,6 @@ const loadingMessages = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
const currentReminder = ref<any>({});
|
||||
|
||||
const formatTime = (timeStr: any) => {
|
||||
if (!timeStr) return "-";
|
||||
const date = new Date(timeStr);
|
||||
return date.toLocaleString();
|
||||
};
|
||||
|
||||
const fetchUnreadCount = async () => {
|
||||
if (!authStore.token) return;
|
||||
try {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { User, Calendar } from "@element-plus/icons-vue";
|
||||
import { readSiteReminder } from "@/api/sitereminder";
|
||||
import { formatTime } from "@/utils/datetime";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
@@ -62,12 +63,6 @@ const getSenderName = (item: any) => {
|
||||
return item.sender_type;
|
||||
};
|
||||
|
||||
const formatTime = (timeStr: any) => {
|
||||
if (!timeStr) return "-";
|
||||
const date = new Date(timeStr);
|
||||
return date.toLocaleString();
|
||||
};
|
||||
|
||||
watch(() => props.modelValue, async (val) => {
|
||||
if (val && props.reminder && !props.viewOnly && props.reminder.is_read === 0) {
|
||||
loading.value = true;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 统一日期时间格式化工具(backend 端)
|
||||
*
|
||||
* 后端(Go)返回的时间字段为 RFC3339 / ISO 8601 字符串,
|
||||
* 例如 "2026-03-31T23:34:07+08:00",直接渲染不友好。
|
||||
* 页面上显示时间统一使用本工具,输出:
|
||||
* formatDateTime / formatTime -> 2026-03-31 23:34:07(YYYY-MM-DD HH:mm:ss)
|
||||
* formatDate / formatDateOnly -> 2026-03-31(YYYY-MM-DD)
|
||||
*/
|
||||
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
|
||||
function toDate(value: any): Date | null {
|
||||
if (value === null || value === undefined || value === "") return null;
|
||||
if (value instanceof Date) return isNaN(value.getTime()) ? null : value;
|
||||
// 兼容秒级 / 毫秒级时间戳
|
||||
if (typeof value === "number") {
|
||||
const d = new Date(value < 1e12 ? value * 1000 : value);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
// "2026-03-31 23:34:07" 形式在部分浏览器解析异常,统一先替换为 ISO 形式
|
||||
const str = String(value).trim().replace(" ", "T");
|
||||
const d = new Date(str);
|
||||
return isNaN(d.getTime()) ? null : d;
|
||||
}
|
||||
|
||||
/** 2026-03-31 23:34:07(YYYY-MM-DD HH:mm:ss);非法值返回 "-" */
|
||||
export function formatDateTime(value: any): string {
|
||||
const d = toDate(value);
|
||||
if (!d) return "-";
|
||||
return (
|
||||
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +
|
||||
`${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
|
||||
);
|
||||
}
|
||||
|
||||
/** 与 formatDateTime 相同(兼容旧调用名) */
|
||||
export function formatTime(value: any): string {
|
||||
return formatDateTime(value);
|
||||
}
|
||||
|
||||
/** 2026-03-31(YYYY-MM-DD);非法值返回 "-";纯日期串不做时区换算 */
|
||||
export function formatDate(value: any): string {
|
||||
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value.trim())) {
|
||||
return value.trim();
|
||||
}
|
||||
const d = toDate(value);
|
||||
if (!d) return "-";
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
||||
}
|
||||
|
||||
/** 与 formatDate 相同(兼容旧调用名) */
|
||||
export function formatDateOnly(value: any): string {
|
||||
return formatDate(value);
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
</span>
|
||||
<span class="meta-item">
|
||||
<i class="el-icon-view"></i>
|
||||
创建日期:{{ model?.create_time }}
|
||||
创建日期:{{ formatDateTime(model?.create_time) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,6 +52,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import { listCategories } from "@/api/article";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
const categoryOptions = ref([]);
|
||||
|
||||
@@ -117,8 +117,12 @@
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column prop="publish_date" label="发布时间" width="160" />
|
||||
<el-table-column prop="update_time" label="更新时间" width="160" />
|
||||
<el-table-column prop="publish_date" label="发布时间" width="160">
|
||||
<template #default="{ row }">{{ formatDate(row.publish_date) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="update_time" label="更新时间" width="160">
|
||||
<template #default="{ row }">{{ formatDateTime(row.update_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="publisher" label="发布人" width="120" />
|
||||
<el-table-column label="操作" width="260" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
@@ -215,6 +219,7 @@ import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
import Edit from "./components/edit.vue";
|
||||
import Preview from "./components/preview.vue";
|
||||
import { formatDate, formatDateTime } from "@/utils/datetime";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import {
|
||||
listArticles,
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="handleEdit(scope.row)"
|
||||
@@ -108,6 +110,7 @@ import { ref, reactive, onMounted } from "vue";
|
||||
import { Plus, Refresh } from "@element-plus/icons-vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import Edit from "./components/edit.vue";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
import { getDemandList, deleteDemand } from "@/api/demand";
|
||||
|
||||
// 状态管理
|
||||
|
||||
@@ -76,7 +76,9 @@
|
||||
<el-tag v-else :type="sslTagType(scope.row.ssl_status)">{{ sslText(scope.row.ssl_status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="申请时间" width="170" />
|
||||
<el-table-column prop="create_time" label="申请时间" width="170">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="230" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<!-- 自有域名无人工审核:解析与证书就绪后自动生效,这里只提供重新检测与禁用 -->
|
||||
@@ -134,6 +136,7 @@
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Refresh } from '@element-plus/icons-vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
import {
|
||||
getTenantDomainList,
|
||||
auditTenantDomain,
|
||||
|
||||
@@ -49,7 +49,9 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="240" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<el-button size="small" text @click="handleEdit(scope.row)">
|
||||
@@ -107,6 +109,7 @@
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Edit, Delete, Refresh, Switch } from '@element-plus/icons-vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
import {
|
||||
getDomainPoolList,
|
||||
createDomainPool,
|
||||
|
||||
@@ -81,7 +81,9 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">
|
||||
@@ -130,6 +132,7 @@ import {
|
||||
deleteFriendlink
|
||||
} from '@/api/friendlink'
|
||||
import EditDialog from './components/edit.vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
// @ts-ignore
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
<el-table-column prop="desc" label="产品描述" min-width="150" align="center" />
|
||||
<el-table-column prop="url" label="跳转地址" min-width="150" align="center" />
|
||||
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">
|
||||
@@ -103,6 +105,7 @@ import {
|
||||
deleteProducts
|
||||
} from '@/api/products'
|
||||
import EditDialog from './components/edit.vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
// @ts-ignore
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
<el-table-column prop="desc" label="分类描述" min-width="200" align="center" />
|
||||
<el-table-column prop="pid" label="父级ID" width="110" align="center" />
|
||||
<el-table-column prop="sort" label="排序" width="90" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" min-width="180" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" min-width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">
|
||||
@@ -81,6 +83,7 @@
|
||||
deleteProductsTypes
|
||||
} from '@/api/products'
|
||||
import EditDialog from './components/edit.vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
|
||||
@@ -65,7 +65,9 @@
|
||||
<el-table-column prop="desc" label="方案描述" min-width="150" align="center" />
|
||||
<el-table-column prop="url" label="跳转地址" min-width="150" align="center" />
|
||||
<el-table-column prop="sort" label="排序" width="80" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">
|
||||
@@ -108,6 +110,7 @@ import {
|
||||
deleteService
|
||||
} from '@/api/services'
|
||||
import EditDialog from './components/edit.vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
// @ts-ignore
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
<el-table-column prop="desc" label="分类描述" min-width="200" align="center" />
|
||||
<el-table-column prop="pid" label="父级ID" width="110" align="center" />
|
||||
<el-table-column prop="sort" label="排序" width="90" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" min-width="180" align="center" />
|
||||
<el-table-column prop="create_time" label="创建时间" min-width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEdit(row)">
|
||||
@@ -81,6 +83,7 @@ import {
|
||||
deleteServicesTypes
|
||||
} from '@/api/services'
|
||||
import EditDialog from './components/edit.vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ contact.create_time || '-' }}
|
||||
{{ contact.create_time ? formatDateTime(contact.create_time) : '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
@@ -108,6 +108,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
|
||||
@@ -299,6 +299,8 @@ import {
|
||||
import { finishSchedule, getScheduleList, getScheduleStats } from "@/api/oaSchedule";
|
||||
import ScheduleDetail from "../schedule/components/detail.vue";
|
||||
import SchedulePostpone from "../schedule/components/postponeDialog.vue";
|
||||
// 时间显示统一为:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
|
||||
const emptyStat = () => ({ total: 0, paid: 0, unpaid: 0, count: 0 });
|
||||
const dashboard = reactive({
|
||||
@@ -607,14 +609,7 @@ const noticeDetailItem = ref(null);
|
||||
const noticeTypeLabel = (type) => ({ 1: "公告", 2: "活动" }[type] || "通知");
|
||||
const noticeTypeTag = (type) => ({ 1: "primary", 2: "success" }[type] || "info");
|
||||
|
||||
const formatDateTime = (value) => {
|
||||
if (!value) return "-";
|
||||
const d = new Date(value);
|
||||
if (Number.isNaN(d.getTime())) return String(value);
|
||||
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${pad2(
|
||||
d.getHours()
|
||||
)}:${pad2(d.getMinutes())}`;
|
||||
};
|
||||
|
||||
|
||||
// 列表右侧时间:今天显示 HH:mm,本年显示 M/D,跨年显示 YYYY-M-D
|
||||
const noticeTime = (item) => {
|
||||
|
||||
@@ -297,6 +297,8 @@ import {
|
||||
summarizeReceiptAmountRows
|
||||
} from '../utils/invoiceAmount'
|
||||
import ItemForm from './itemForm.vue'
|
||||
// 时间显示统一为:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
@@ -913,7 +915,6 @@ const removeReceipt = async receipt => {
|
||||
|
||||
const actionLabel = value => ({ 1: '提交申请', 2: '审批通过', 3: '审批驳回', 4: '转审', 5: '撤回' })[value] || '审批操作'
|
||||
const money = value => Number(value || 0).toFixed(2)
|
||||
const formatDateTime = value => value ? new Date(value).toLocaleString('zh-CN', { hour12: false }) : '-'
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -169,6 +169,8 @@ import { Plus, Refresh, Search, Setting } from "@element-plus/icons-vue";
|
||||
import ReimburseEdit from "./components/edit.vue";
|
||||
import ReimburseDetail from "./components/detail.vue";
|
||||
import ExpenseTypeDialog from "./components/expenseTypeDialog.vue";
|
||||
// 日期/时间显示统一格式:YYYY-MM-DD 与 YYYY-MM-DD HH:mm:ss
|
||||
import { formatDate as formatDateUtil, formatDateTime } from "@/utils/datetime";
|
||||
import { exportReimbursementPdf } from "./utils/exportReimbursementPdf";
|
||||
import {
|
||||
createReimbursement,
|
||||
@@ -351,15 +353,11 @@ const handleExport = async (row) => {
|
||||
};
|
||||
|
||||
const money = (value) => Number(value || 0).toFixed(2);
|
||||
const formatDate = (value) => {
|
||||
// 日期显示统一为:YYYY-MM-DD
|
||||
const formatDate = (value: any) => {
|
||||
if (!value) return "-";
|
||||
const text = String(value);
|
||||
const match = text.match(/^(\d{4}-\d{2}-\d{2})/);
|
||||
if (match) return match[1];
|
||||
return text;
|
||||
return formatDateUtil(value);
|
||||
};
|
||||
const formatDateTime = (value) =>
|
||||
value ? new Date(value).toLocaleString("zh-CN", { hour12: false }) : "-";
|
||||
const statusLabel = (value) =>
|
||||
statusOptions.find((item) => item.value === value)?.label || "未知";
|
||||
const statusType = (value) =>
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ roleDetail.create_time }}
|
||||
{{ formatDateTime(roleDetail.create_time) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">
|
||||
{{ roleDetail.update_time }}
|
||||
{{ formatDateTime(roleDetail.update_time) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
@@ -56,6 +56,7 @@ import { ref, watch, computed } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { getRoleById } from "@/api/role";
|
||||
import { getAssignableMenus } from "@/api/menu";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
|
||||
interface Props {
|
||||
modelValue: boolean;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="filter-bar">
|
||||
<el-radio-group v-model="typeFilter">
|
||||
<el-radio-button :value="'all'">全部</el-radio-button>
|
||||
<el-radio-button :value="2">租户角色</el-radio-button>
|
||||
<el-radio-button :value="'global'">全局角色</el-radio-button>
|
||||
<el-radio-button :value="'custom'">自定义角色</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
@@ -41,7 +41,9 @@
|
||||
/>
|
||||
<el-table-column prop="cid" label="类型" width="150" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.cid === 1" type="danger" size="small">平台角色</el-tag>
|
||||
<el-tag v-if="Number(row.tenant_id || 0) === 0" type="success" size="small">
|
||||
全局角色
|
||||
</el-tag>
|
||||
<el-tag v-else-if="Number(row.is_custom) === 1" type="warning" size="small">
|
||||
自定义角色
|
||||
</el-tag>
|
||||
@@ -73,6 +75,7 @@
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="Number(row.tenant_id || 0) > 0"
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@@ -124,8 +127,9 @@ const loading = ref(false);
|
||||
const error = ref("");
|
||||
const typeFilter = ref<string | number>("all");
|
||||
const displayRoles = computed(() => {
|
||||
// custom = 本租户自建的自定义角色;2 = 租户角色(含系统预置)
|
||||
// global = 全局角色(所有租户共用,平台端维护);custom = 本租户自建的自定义角色
|
||||
if (typeFilter.value === "all") return roles.value;
|
||||
if (typeFilter.value === "global") return roles.value.filter((r) => Number(r.tenant_id || 0) === 0);
|
||||
if (typeFilter.value === "custom") return roles.value.filter((r) => Number(r.is_custom) === 1);
|
||||
return roles.value.filter((r) => Number(r.cid) === Number(typeFilter.value));
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ detailData.create_time || '-' }}
|
||||
{{ detailData.create_time ? formatDateTime(detailData.create_time) : '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
import { ref } from "vue";
|
||||
import { getTenantDetail } from "@/api/tenant";
|
||||
import TenantUsersTab from "./TenantUsersTab.vue";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
|
||||
const visible = ref(false);
|
||||
const loading = ref(false);
|
||||
|
||||
@@ -90,7 +90,9 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="申请时间" width="170" />
|
||||
<el-table-column prop="create_time" label="申请时间" width="170">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="230" fixed="right" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -238,6 +240,7 @@
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { Plus, Link } from "@element-plus/icons-vue";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
import {
|
||||
getMyDomains,
|
||||
applyTenantDomain,
|
||||
|
||||
@@ -48,10 +48,10 @@
|
||||
{{ user.login_count || 0 }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ user.create_time || "未知" }}
|
||||
{{ user.create_time ? formatDateTime(user.create_time) : "未知" }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间" :span="2">
|
||||
{{ user.update_time || "未知" }}
|
||||
{{ user.update_time ? formatDateTime(user.update_time) : "未知" }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
@@ -66,6 +66,7 @@
|
||||
import { ref, watch } from "vue";
|
||||
import { UserFilled } from "@element-plus/icons-vue";
|
||||
import { getAllRoles } from "@/api/role";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 角色(关联 yz_system_admin_role, cid=2) -->
|
||||
<!-- 角色(关联 yz_system_admin_role, cid=2):平台默认角色 + 租户自定义角色 -->
|
||||
<el-form-item label="角色">
|
||||
<el-select
|
||||
v-model="form.group_id"
|
||||
@@ -79,12 +79,22 @@
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="role in roles"
|
||||
:key="role.id"
|
||||
:label="role.name"
|
||||
:value="role.id"
|
||||
/>
|
||||
<el-option-group v-if="globalRoles.length" label="平台默认角色">
|
||||
<el-option
|
||||
v-for="role in globalRoles"
|
||||
:key="role.id"
|
||||
:label="role.name"
|
||||
:value="role.id"
|
||||
/>
|
||||
</el-option-group>
|
||||
<el-option-group v-if="customRoles.length" label="租户自定义角色">
|
||||
<el-option
|
||||
v-for="role in customRoles"
|
||||
:key="role.id"
|
||||
:label="role.name"
|
||||
:value="role.id"
|
||||
/>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -142,6 +152,7 @@ interface RoleOption {
|
||||
id: number;
|
||||
name: string;
|
||||
status?: number;
|
||||
tenant_id?: number;
|
||||
}
|
||||
|
||||
const roles = ref<RoleOption[]>([]);
|
||||
@@ -155,6 +166,15 @@ const fetchRoles = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 平台规定的默认角色(全局角色,tenant_id=0,平台端统一维护)
|
||||
const globalRoles = computed(() =>
|
||||
roles.value.filter((r) => Number(r.tenant_id || 0) === 0)
|
||||
);
|
||||
// 租户自己建立的角色(tenant_id=当前租户)
|
||||
const customRoles = computed(() =>
|
||||
roles.value.filter((r) => Number(r.tenant_id || 0) > 0)
|
||||
);
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
return isAdd.value ? "添加用户" : "编辑用户";
|
||||
});
|
||||
|
||||
@@ -100,6 +100,8 @@ import { Plus, Edit, Delete } from "@element-plus/icons-vue";
|
||||
import type { FormInstance, FormRules } from "element-plus";
|
||||
|
||||
import { getModuleCategory,editModuleCategory } from "@/api/moduleCenter";
|
||||
// 该页面展示精确到秒的时间:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime as formatDate } from "@/utils/datetime";
|
||||
|
||||
interface Category {
|
||||
id: number;
|
||||
@@ -160,16 +162,7 @@ const getStatusType = (status: number) => {
|
||||
return map[status] || "info";
|
||||
};
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
if (!date) return "-";
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
const hours = String(d.getHours()).padStart(2, "0");
|
||||
const minutes = String(d.getMinutes()).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
|
||||
const handleCategoryAdd = () => {
|
||||
isEdit.value = false;
|
||||
|
||||
@@ -146,6 +146,8 @@ import type { FormInstance, FormRules } from "element-plus";
|
||||
import { getModules, getModuleCategory,editModules } from "@/api/moduleCenter";
|
||||
import CreateModules from "../components/createModules.vue";
|
||||
import { uploadFile } from '@/api/file.js';
|
||||
// 该页面展示精确到秒的时间:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime as formatDate } from "@/utils/datetime";
|
||||
|
||||
interface Module {
|
||||
id: number;
|
||||
@@ -266,16 +268,7 @@ function handlePictureCardPreview(file: any) {
|
||||
|
||||
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
if (!date) return "-";
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
const hours = String(d.getHours()).padStart(2, "0");
|
||||
const minutes = String(d.getMinutes()).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
|
||||
const handleCreate = () => {
|
||||
createDialogVisible.value = true;
|
||||
|
||||
@@ -175,6 +175,8 @@ import { Plus, View, Delete, UploadFilled, Document } from "@element-plus/icons-
|
||||
import type { FormInstance, FormRules, UploadFile } from "element-plus";
|
||||
|
||||
import { getModules, getModuleCategory } from "@/api/moduleCenter";
|
||||
// 该页面展示精确到秒的时间:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime as formatDate } from "@/utils/datetime";
|
||||
|
||||
interface Publish {
|
||||
id: number;
|
||||
@@ -245,16 +247,7 @@ const getStatusType = (status: number) => {
|
||||
return map[status] || "info";
|
||||
};
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
if (!date) return "-";
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
const hours = String(d.getHours()).padStart(2, "0");
|
||||
const minutes = String(d.getMinutes()).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
|
||||
const handlePublish = () => {
|
||||
publishDialogVisible.value = true;
|
||||
|
||||
@@ -139,11 +139,12 @@
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { InfoFilled, Refresh, DocumentCopy } from '@element-plus/icons-vue';
|
||||
import { formatDateTime } from '@/utils/datetime';
|
||||
|
||||
// 系统信息数据
|
||||
const loading = ref(false);
|
||||
const systemInfo = ref<any>({});
|
||||
const currentTime = ref(new Date().toLocaleString('zh-CN'));
|
||||
const currentTime = ref(formatDateTime(new Date()));
|
||||
|
||||
// API基础地址
|
||||
const apiBaseUrl = computed(() => {
|
||||
@@ -251,7 +252,7 @@ async function fetchSystemInfo() {
|
||||
// 刷新信息
|
||||
function refreshInfo() {
|
||||
fetchSystemInfo();
|
||||
currentTime.value = new Date().toLocaleString('zh-CN');
|
||||
currentTime.value = formatDateTime(new Date());
|
||||
ElMessage.success('信息已刷新');
|
||||
}
|
||||
|
||||
@@ -285,7 +286,7 @@ function copySystemInfo() {
|
||||
- 屏幕分辨率:${clientInfo.value.screenResolution}
|
||||
- 设备类型:${clientInfo.value.isMobile ? '移动设备' : '桌面设备'}
|
||||
|
||||
生成时间:${new Date().toLocaleString('zh-CN')}`;
|
||||
生成时间:${formatDateTime(new Date())}`;
|
||||
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(infoText).then(() => {
|
||||
@@ -315,7 +316,7 @@ onMounted(() => {
|
||||
fetchSystemInfo();
|
||||
// 每秒更新时间
|
||||
timeInterval = setInterval(() => {
|
||||
currentTime.value = new Date().toLocaleString('zh-CN');
|
||||
currentTime.value = formatDateTime(new Date());
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
||||
@@ -216,21 +216,13 @@
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 格式化日期
|
||||
// 日期显示统一为:YYYY-MM-DD HH:mm:ss
|
||||
function formatDate(dateStr: string | null | undefined): string {
|
||||
if (!dateStr) return ''
|
||||
try {
|
||||
const date = new Date(dateStr)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
} catch {
|
||||
return dateStr as string
|
||||
}
|
||||
const d = new Date(dateStr)
|
||||
if (isNaN(d.getTime())) return String(dateStr)
|
||||
const p = (n: number) => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
|
||||
}
|
||||
|
||||
// 获取字典类型列表(用于下拉选择)
|
||||
|
||||
@@ -156,21 +156,13 @@
|
||||
return result
|
||||
})
|
||||
|
||||
// 格式化日期
|
||||
// 日期显示统一为:YYYY-MM-DD HH:mm:ss
|
||||
function formatDate(dateStr: string | null | undefined): string {
|
||||
if (!dateStr) return ''
|
||||
try {
|
||||
const date = new Date(dateStr)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
} catch {
|
||||
return dateStr as string
|
||||
}
|
||||
const d = new Date(dateStr)
|
||||
if (isNaN(d.getTime())) return String(dateStr)
|
||||
const p = (n: number) => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`
|
||||
}
|
||||
|
||||
// 获取字典类型列表
|
||||
|
||||
@@ -149,6 +149,7 @@ import {
|
||||
} from '@/api/dict'
|
||||
import DictTypeEdit from './components/DictTypeEdit.vue'
|
||||
import DictItemList from './components/DictItemList.vue'
|
||||
import { formatDateTime } from '@/utils/datetime'
|
||||
|
||||
const currentView = ref<'types' | 'items'>('types')
|
||||
const typeLoading = ref(false)
|
||||
@@ -172,21 +173,9 @@ const selectedDictType = computed(() => {
|
||||
return dictTypes.value.find((type) => type.id === selectedDictTypeId.value) || null
|
||||
})
|
||||
|
||||
// 格式化日期
|
||||
// 日期显示统一为:YYYY-MM-DD HH:mm:ss(utils/datetime)
|
||||
function formatDate(dateStr: string | null | undefined): string {
|
||||
if (!dateStr) return ''
|
||||
try {
|
||||
const date = new Date(dateStr)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
} catch {
|
||||
return dateStr as string
|
||||
}
|
||||
return dateStr ? formatDateTime(dateStr) : ''
|
||||
}
|
||||
|
||||
// 获取字典类型列表
|
||||
|
||||
@@ -496,6 +496,8 @@ import UploadFile from "./components/uploadFile.vue";
|
||||
import MoveFile from "./components/moveFile.vue";
|
||||
import RenameCategory from "./components/renameCategory.vue";
|
||||
import CreateCategory from "./components/createCategory.vue";
|
||||
// 日期显示统一为:YYYY-MM-DD
|
||||
import { formatDate } from "@/utils/datetime";
|
||||
|
||||
// 分组相关
|
||||
interface Group {
|
||||
@@ -872,14 +874,7 @@ const formatFileSize = (bytes: number): string => {
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr: string): string => {
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleDateString("zh-CN", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 文件操作
|
||||
const handleFileClick = (file: FileItem) => {
|
||||
|
||||
@@ -124,12 +124,9 @@
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="ip" label="IP地址" width="130" align="center" />
|
||||
<el-table-column
|
||||
prop="create_time"
|
||||
label="登录时间"
|
||||
width="180"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column prop="create_time" label="登录时间" width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -192,6 +189,7 @@ import {
|
||||
batchDeleteLoginLogs,
|
||||
} from "@/api/loginLog";
|
||||
import DetailDialog from "./components/detail.vue";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
|
||||
interface LoginLog {
|
||||
id: number;
|
||||
|
||||
@@ -117,12 +117,9 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="create_time"
|
||||
label="操作时间"
|
||||
width="180"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column prop="create_time" label="操作时间" width="180" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
@@ -170,6 +167,7 @@ import {
|
||||
getOperationStatistics,
|
||||
} from "@/api/operationLog";
|
||||
import DetailDialog from "./components/detail.vue";
|
||||
import { formatDateTime } from "@/utils/datetime";
|
||||
|
||||
interface OperationLog {
|
||||
id: number;
|
||||
|
||||
@@ -77,6 +77,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Plus, Search, Delete, MoreFilled } from '@element-plus/icons-vue';
|
||||
import NoteEditor from './components/edit.vue';
|
||||
import { getNotebookList, deleteNotebook } from '@/api/notebook';
|
||||
import { formatDate } from '@/utils/datetime';
|
||||
|
||||
const searchKeyword = ref('');
|
||||
const currentNoteId = ref(null);
|
||||
@@ -117,11 +118,7 @@ const formatTime = (dateStr) => {
|
||||
} else if (diff < 7 * day) {
|
||||
return `${Math.floor(diff / day)} 天前`;
|
||||
} else {
|
||||
return date.toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
});
|
||||
return formatDate(date);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -61,6 +61,8 @@ import { useRouter } from "vue-router";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { getUserInfo } from "@/api/user";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
// 该页面展示精确到秒的时间:YYYY-MM-DD HH:mm:ss
|
||||
import { formatDateTime as formatDate } from "@/utils/datetime";
|
||||
import ProfileCard from "./components/ProfileCard.vue";
|
||||
import QuickActions from "./components/QuickActions.vue";
|
||||
import DetailCard from "./components/DetailCard.vue";
|
||||
@@ -79,16 +81,7 @@ const passwordDialogVisible = ref(false);
|
||||
const bindPhoneDialogVisible = ref(false);
|
||||
const bindEmailDialogVisible = ref(false);
|
||||
|
||||
const formatDate = (date) => {
|
||||
if (!date) return "-";
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
const hours = String(d.getHours()).padStart(2, "0");
|
||||
const minutes = String(d.getMinutes()).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
|
||||
const getSexText = (sex) => {
|
||||
const map = {
|
||||
|
||||
Reference in New Issue
Block a user