19 changed files with 637 additions and 22 deletions
@ -0,0 +1,3 @@ |
|||
NODE_ENV=development |
|||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
|||
VITE_APP_API_URL='http://127.0.0.1:1024' |
|||
@ -0,0 +1,3 @@ |
|||
NODE_ENV=development |
|||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
|||
VITE_APP_API_URL='http://127.0.0.1:1024' |
|||
@ -0,0 +1,3 @@ |
|||
NODE_ENV=production |
|||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
|||
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api' |
|||
@ -0,0 +1,3 @@ |
|||
NODE_ENV=production |
|||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
|||
VITE_APP_API_URL='https://preview.smartadmin.vip/smart-admin-api' |
|||
@ -0,0 +1,3 @@ |
|||
NODE_ENV=production |
|||
VITE_APP_TITLE='律师公益法律服务活动申报与管理平台' |
|||
VITE_APP_API_URL='http://127.0.0.1:1024' |
|||
@ -0,0 +1,18 @@ |
|||
|
|||
*.sh |
|||
node_modules |
|||
lib |
|||
*.md |
|||
*.woff |
|||
*.ttf |
|||
.vscode |
|||
.idea |
|||
dist |
|||
public |
|||
/docs |
|||
.husky |
|||
.local |
|||
.localhost |
|||
/bin |
|||
Dockerfile |
|||
src/assets |
|||
@ -0,0 +1,66 @@ |
|||
/* |
|||
* @Description: |
|||
* @Author: zhuoda |
|||
* @Date: 2021-11-05 |
|||
* @LastEditTime: 2022-07-05 |
|||
* @LastEditors: zhuoda |
|||
*/ |
|||
module.exports = { |
|||
root: true, //此项是用来告诉eslint找当前配置文件不能往父级查找 |
|||
env: { |
|||
browser: true, |
|||
es2021: true, |
|||
node: true, |
|||
}, |
|||
parser: 'vue-eslint-parser', //使用vue-eslint-parser 来解析vue文件中的 template和script |
|||
parserOptions: { |
|||
ecmaVersion: 12, // 默认情况下,ESLint使用的是ECMAScript5语法,此处我们设置的选项是 es12 |
|||
sourceType: 'module', // 指定js导入的方式 |
|||
}, |
|||
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', 'plugin:vue/base'], |
|||
globals: { |
|||
defineProps: 'readonly', |
|||
defineEmits: 'readonly', |
|||
defineExpose: 'readonly', |
|||
withDefaults: 'readonly', |
|||
}, |
|||
plugins: ['vue'], |
|||
rules: { |
|||
'no-unused-vars': [ |
|||
'error', |
|||
// we are only using this rule to check for unused arguments since TS |
|||
// catches unused variables but not args. |
|||
{ varsIgnorePattern: '.*', args: 'none' }, |
|||
], |
|||
'space-before-function-paren': 'off', |
|||
|
|||
'vue/attributes-order': 'off', |
|||
'vue/one-component-per-file': 'off', |
|||
'vue/html-closing-bracket-newline': 'off', |
|||
'vue/max-attributes-per-line': 'off', |
|||
'vue/multiline-html-element-content-newline': 'off', |
|||
'vue/singleline-html-element-content-newline': 'off', |
|||
'vue/attribute-hyphenation': 'off', |
|||
'vue/require-default-prop': 'off', |
|||
'vue/multi-word-component-names': [ |
|||
'error', |
|||
{ |
|||
ignores: ['index'], //需要忽略的组件名 |
|||
}, |
|||
], |
|||
'vue/html-self-closing': [ |
|||
'error', |
|||
{ |
|||
html: { |
|||
void: 'always', |
|||
normal: 'never', |
|||
component: 'always', |
|||
}, |
|||
svg: 'always', |
|||
math: 'always', |
|||
}, |
|||
], |
|||
// Enable vue/script-setup-uses-vars rule |
|||
'vue/script-setup-uses-vars': 'error', |
|||
}, |
|||
}; |
|||
@ -0,0 +1,7 @@ |
|||
node_modules |
|||
.DS_Store |
|||
**/.DS_Store |
|||
dist |
|||
dist-ssr |
|||
*.local |
|||
.idea |
|||
@ -0,0 +1,30 @@ |
|||
/* |
|||
* 代码格式化配置 |
|||
* |
|||
* @Author: 1024创新实验室-主任:卓大 |
|||
* @Date: 2022-09-12 14:44:18 |
|||
* @Wechat: zhuda1024 |
|||
* @Email: lab1024@163.com |
|||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 |
|||
*/ |
|||
module.exports = { |
|||
printWidth: 150, // 每行代码长度(默认80) |
|||
tabWidth: 2, // 缩进空格数 |
|||
useTabs: false, //不用tab缩进 |
|||
semi: true, //// 在语句末尾打印分号 |
|||
singleQuote: true, // 使用单引号而不是双引号 |
|||
vueIndentScriptAndStyle: true, //Vue文件脚本和样式标签缩进 |
|||
quoteProps: 'as-needed', // 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>" |
|||
jsxSingleQuote: true, // 在JSX中使用单引号而不是双引号 |
|||
trailingComma: 'es5', //多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none |
|||
bracketSpacing: true, // 在对象文字中的括号之间打印空格 |
|||
jsxBracketSameLine: false, //jsx 标签的反尖括号需要换行 |
|||
arrowParens: 'always', // 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x |
|||
rangeStart: 0, // 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码 |
|||
rangeEnd: Infinity, |
|||
requirePragma: false, // 指定要使用的解析器,不需要写文件开头的 @prettier |
|||
insertPragma: false, // 不需要自动在文件开头插入 @prettier |
|||
proseWrap: 'preserve', // 使用默认的折行标准 always\never\preserve |
|||
htmlWhitespaceSensitivity: 'css', // 指定HTML文件的全局空格敏感度 css\strict\ignore |
|||
endOfLine: 'auto', // 因为prettier的规范和eslint的换行规则不同,所以这个必须配置。要不然每次打开文件都会有一堆的警告;换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr |
|||
}; |
|||
@ -0,0 +1,3 @@ |
|||
/dist/* |
|||
/public/* |
|||
public/* |
|||
@ -0,0 +1,70 @@ |
|||
module.exports = { |
|||
root: true, |
|||
plugins: ['stylelint-order'], |
|||
extends: ['stylelint-config-standard', 'stylelint-config-prettier'], |
|||
rules: { |
|||
'selector-pseudo-class-no-unknown': [ |
|||
true, |
|||
{ |
|||
ignorePseudoClasses: ['global'], |
|||
}, |
|||
], |
|||
'selector-pseudo-element-no-unknown': [ |
|||
true, |
|||
{ |
|||
ignorePseudoElements: ['v-deep'], |
|||
}, |
|||
], |
|||
'at-rule-no-unknown': [ |
|||
true, |
|||
{ |
|||
ignoreAtRules: [ |
|||
'tailwind', |
|||
'apply', |
|||
'variants', |
|||
'responsive', |
|||
'screen', |
|||
'function', |
|||
'if', |
|||
'each', |
|||
'include', |
|||
'mixin', |
|||
], |
|||
}, |
|||
], |
|||
'no-empty-source': null, |
|||
'named-grid-areas-no-invalid': null, |
|||
'unicode-bom': 'never', |
|||
'no-descending-specificity': null, |
|||
'font-family-no-missing-generic-family-keyword': null, |
|||
'declaration-colon-space-after': 'always-single-line', |
|||
'declaration-colon-space-before': 'never', |
|||
// 'declaration-block-trailing-semicolon': 'always',
|
|||
'rule-empty-line-before': [ |
|||
'always', |
|||
{ |
|||
ignore: ['after-comment', 'first-nested'], |
|||
}, |
|||
], |
|||
'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }], |
|||
'order/order': [ |
|||
[ |
|||
'dollar-variables', |
|||
'custom-properties', |
|||
'at-rules', |
|||
'declarations', |
|||
{ |
|||
type: 'at-rule', |
|||
name: 'supports', |
|||
}, |
|||
{ |
|||
type: 'at-rule', |
|||
name: 'media', |
|||
}, |
|||
'rules', |
|||
], |
|||
{ severity: 'warning' }, |
|||
], |
|||
}, |
|||
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'], |
|||
}; |
|||
@ -0,0 +1,3 @@ |
|||
{ |
|||
"search.useGlobalIgnoreFiles": true |
|||
} |
|||
@ -0,0 +1,235 @@ |
|||
<!-- |
|||
* 季度统计组件 |
|||
* |
|||
* @Author: wzh |
|||
* @Date: 2025-12-24 14:44:06 |
|||
* @Copyright 1.0 |
|||
--> |
|||
<template> |
|||
<div class="quarter-statistics"> |
|||
<!-- 查询表单 --> |
|||
<a-card title="查询条件" size="small" class="query-card"> |
|||
<a-form :model="queryForm" layout="inline"> |
|||
<a-form-item label="季度"> |
|||
<a-select v-model:value="queryForm.quarter" placeholder="请选择季度" style="width: 120px"> |
|||
<a-select-option v-for="quarter in quarterOptions" :key="quarter.value" :value="quarter.value"> |
|||
{{ quarter.label }} |
|||
</a-select-option> |
|||
</a-select> |
|||
</a-form-item> |
|||
|
|||
<a-form-item label="年度"> |
|||
<a-select v-model:value="queryForm.year" placeholder="请选择年度" style="width: 120px"> |
|||
<a-select-option v-for="year in yearOptions" :key="year" :value="year"> |
|||
{{ year }}年 |
|||
</a-select-option> |
|||
</a-select> |
|||
</a-form-item> |
|||
|
|||
<a-form-item label="律师姓名"> |
|||
<a-input v-model:value="queryForm.lawyerName" placeholder="请输入律师姓名" style="width: 150px" /> |
|||
</a-form-item> |
|||
|
|||
<a-form-item label="律所名称"> |
|||
<a-input v-model:value="queryForm.firmName" placeholder="请输入律所名称" style="width: 150px" /> |
|||
</a-form-item> |
|||
|
|||
<a-form-item> |
|||
<a-button type="primary" @click="handleSearch"> |
|||
<SearchOutlined /> |
|||
查询 |
|||
</a-button> |
|||
<a-button @click="handleReset" style="margin-left: 8px"> |
|||
<ReloadOutlined /> |
|||
重置 |
|||
</a-button> |
|||
<a-button @click="handleExport" type="primary" style="margin-left: 8px"> |
|||
<ExportOutlined /> |
|||
导出Excel |
|||
</a-button> |
|||
</a-form-item> |
|||
</a-form> |
|||
</a-card> |
|||
|
|||
<!-- 统计表格 --> |
|||
<a-card title="季度服务统计" size="small" class="table-card"> |
|||
<a-table |
|||
:columns="columns" |
|||
:dataSource="tableData" |
|||
:pagination="pagination" |
|||
:loading="loading" |
|||
size="small" |
|||
bordered |
|||
> |
|||
<template #bodyCell="{ column, record }"> |
|||
<template v-if="column.dataIndex === 'quarterDuration'"> |
|||
{{ record.quarterDuration }} 小时 |
|||
</template> |
|||
<template v-else-if="column.dataIndex === 'quarterCost'"> |
|||
{{ record.quarterCost }} 元 |
|||
</template> |
|||
<template v-else-if="column.dataIndex === 'yearDuration'"> |
|||
{{ record.yearDuration }} 小时 |
|||
</template> |
|||
<template v-else-if="column.dataIndex === 'yearCost'"> |
|||
{{ record.yearCost }} 元 |
|||
</template> |
|||
</template> |
|||
</a-table> |
|||
</a-card> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, reactive, onMounted } from 'vue'; |
|||
import { SearchOutlined, ReloadOutlined, ExportOutlined } from '@ant-design/icons-vue'; |
|||
import { message } from 'ant-design-vue'; |
|||
import { serviceApplicationsApi } from '/@/api/business/service-applications/service-applications-api'; |
|||
|
|||
// 查询表单 |
|||
const queryForm = reactive({ |
|||
quarter: undefined, |
|||
year: new Date().getFullYear(), |
|||
lawyerName: '', |
|||
firmName: '' |
|||
}); |
|||
|
|||
// 季度选项 |
|||
const quarterOptions = [ |
|||
{ label: '第一季度', value: 1 }, |
|||
{ label: '第二季度', value: 2 }, |
|||
{ label: '第三季度', value: 3 }, |
|||
{ label: '第四季度', value: 4 } |
|||
]; |
|||
|
|||
// 年度选项(近5年) |
|||
const yearOptions = ref([]); |
|||
|
|||
// 表格列定义 |
|||
const columns = [ |
|||
{ |
|||
title: '执业律师姓名', |
|||
dataIndex: 'lawyerName', |
|||
key: 'lawyerName', |
|||
width: 120 |
|||
}, |
|||
{ |
|||
title: '执业证号', |
|||
dataIndex: 'certificateNumber', |
|||
key: 'certificateNumber', |
|||
width: 120 |
|||
}, |
|||
{ |
|||
title: '季度累计服务时长', |
|||
dataIndex: 'quarterDuration', |
|||
key: 'quarterDuration', |
|||
width: 120 |
|||
}, |
|||
{ |
|||
title: '季度累计服务成本', |
|||
dataIndex: 'quarterCost', |
|||
key: 'quarterCost', |
|||
width: 120 |
|||
}, |
|||
{ |
|||
title: '年度累计服务时长', |
|||
dataIndex: 'yearDuration', |
|||
key: 'yearDuration', |
|||
width: 120 |
|||
}, |
|||
{ |
|||
title: '年度累计服务成本', |
|||
dataIndex: 'yearCost', |
|||
key: 'yearCost', |
|||
width: 120 |
|||
} |
|||
]; |
|||
|
|||
const tableData = ref([]); |
|||
const loading = ref(false); |
|||
const pagination = reactive({ |
|||
current: 1, |
|||
pageSize: 10, |
|||
total: 0, |
|||
showSizeChanger: true, |
|||
showQuickJumper: true, |
|||
showTotal: (total) => `共 ${total} 条` |
|||
}); |
|||
|
|||
// 初始化年度选项 |
|||
function initYearOptions() { |
|||
const currentYear = new Date().getFullYear(); |
|||
for (let i = currentYear; i >= currentYear - 4; i--) { |
|||
yearOptions.value.push(i); |
|||
} |
|||
} |
|||
|
|||
// 查询数据 |
|||
async function handleSearch() { |
|||
loading.value = true; |
|||
try { |
|||
const params = { |
|||
...queryForm, |
|||
pageNum: pagination.current, |
|||
pageSize: pagination.pageSize |
|||
}; |
|||
|
|||
// 调用API获取季度统计数据 |
|||
const result = await serviceApplicationsApi.getQuarterStatistics(params); |
|||
|
|||
if (result.data) { |
|||
tableData.value = result.data.list || []; |
|||
pagination.total = result.data.total || 0; |
|||
} |
|||
} catch (error) { |
|||
message.error('查询失败'); |
|||
console.error(error); |
|||
} finally { |
|||
loading.value = false; |
|||
} |
|||
} |
|||
|
|||
// 重置查询条件 |
|||
function handleReset() { |
|||
Object.assign(queryForm, { |
|||
quarter: undefined, |
|||
year: new Date().getFullYear(), |
|||
lawyerName: '', |
|||
firmName: '' |
|||
}); |
|||
handleSearch(); |
|||
} |
|||
|
|||
// 导出Excel |
|||
function handleExport() { |
|||
message.info('导出功能开发中...'); |
|||
// 这里调用导出API |
|||
// await serviceApplicationsApi.exportQuarterStatistics(queryForm); |
|||
} |
|||
|
|||
// 分页变化 |
|||
function handleTableChange(pag) { |
|||
pagination.current = pag.current; |
|||
pagination.pageSize = pag.pageSize; |
|||
handleSearch(); |
|||
} |
|||
|
|||
onMounted(() => { |
|||
initYearOptions(); |
|||
handleSearch(); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.quarter-statistics { |
|||
padding: 0; |
|||
} |
|||
|
|||
.query-card { |
|||
margin-bottom: 16px; |
|||
} |
|||
|
|||
.table-card { |
|||
margin-bottom: 0; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,30 @@ |
|||
<!-- |
|||
* 服务申报统计 |
|||
* |
|||
* @Author: wzh |
|||
* @Date: 2025-12-24 14:44:06 |
|||
* @Copyright 1.0 |
|||
--> |
|||
<template> |
|||
<div class="service-application-count"> |
|||
<a-tabs v-model:activeKey="activeTab" type="card"> |
|||
<!-- 季度统计 --> |
|||
<a-tab-pane key="quarter" tab="季度统计"> |
|||
<QuarterStatistics /> |
|||
</a-tab-pane> |
|||
</a-tabs> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue'; |
|||
import QuarterStatistics from '/@/components/system/service-count/quarter-statistics.vue'; |
|||
const activeTab = ref('quarter'); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.service-application-count { |
|||
padding: 16px; |
|||
background: #fff; |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue