개인정보 관련 업데이트 진행
ot 정보는 타인이 못봄 휴가신청 관련건도 타인이 못봄
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>Full</DebugType>
|
||||
<Optimize>False</Optimize>
|
||||
<OutputPath>..\..\..\..\amkor\GroupWare\</OutputPath>
|
||||
<OutputPath>..\..\..\..\Amkor\GroupWare\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;WEB1</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
@@ -671,21 +671,6 @@
|
||||
<Content Include="Web\wwwroot\Project\index.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Web\wwwroot\react\LoginApp.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\TestApp.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\DashboardApp.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\CommonNavigation.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\CommonCode.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\css\common.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -722,18 +707,6 @@
|
||||
<None Include="Web\wwwroot\login.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\JobReport.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\Kuntae.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\Todo.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\Project.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\lib\js\react.development.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -749,9 +722,6 @@
|
||||
<None Include="Web\wwwroot\lib\js\tailwind-config.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Web\wwwroot\react\DevWarning.jsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호가 자동으로
|
||||
// 지정되도록 할 수 있습니다.
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("25.11.03.1350")]
|
||||
[assembly: AssemblyFileVersion("25.11.03.1350")]
|
||||
[assembly: AssemblyVersion("25.11.11.1030")]
|
||||
[assembly: AssemblyFileVersion("25.11.11.1030")]
|
||||
|
||||
@@ -18,7 +18,34 @@ namespace Project.OWIN
|
||||
{
|
||||
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
|
||||
|
||||
// 정적 파일 서빙을 가장 먼저 설정 (다른 모든 미들웨어보다 우선)
|
||||
// 캐시 방지 미들웨어를 가장 먼저 설정 (정적 파일 서빙보다 우선)
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var path = context.Request.Path.Value;
|
||||
|
||||
// 모든 정적 리소스에 대해 캐시 방지 헤더 설정
|
||||
if (path.EndsWith(".js") ||
|
||||
path.EndsWith(".css") ||
|
||||
path.EndsWith(".jsx") ||
|
||||
path.EndsWith(".tsx") ||
|
||||
path.EndsWith(".html") ||
|
||||
path.EndsWith(".htm"))
|
||||
{
|
||||
context.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
|
||||
context.Response.Headers["Pragma"] = "no-cache";
|
||||
context.Response.Headers["Expires"] = "0";
|
||||
}
|
||||
|
||||
// JSX/TSX 파일을 JavaScript로 처리
|
||||
if (path.EndsWith(".jsx") || path.EndsWith(".tsx"))
|
||||
{
|
||||
context.Response.ContentType = "application/javascript; charset=utf-8";
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
// 정적 파일 서빙 설정
|
||||
var staticFileOptions = new FileServerOptions
|
||||
{
|
||||
EnableDefaultFiles = true,
|
||||
@@ -28,31 +55,6 @@ namespace Project.OWIN
|
||||
};
|
||||
app.UseFileServer(staticFileOptions);
|
||||
|
||||
// 캐시 방지 미들웨어 (정적 파일이 처리되지 않은 경우에만 적용)
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var path = context.Request.Path.Value;
|
||||
|
||||
if (path.EndsWith(".js") ||
|
||||
path.EndsWith(".css") ||
|
||||
path.EndsWith(".jsx") ||
|
||||
path.EndsWith(".tsx") ||
|
||||
path.EndsWith(".html"))
|
||||
{
|
||||
context.Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
|
||||
context.Response.Headers["Pragma"] = "no-cache";
|
||||
context.Response.Headers["Expires"] = "0";
|
||||
}
|
||||
|
||||
// JSX/TSX 파일을 JavaScript로 처리
|
||||
if (path.EndsWith(".jsx") || path.EndsWith(".tsx"))
|
||||
{
|
||||
context.Response.ContentType = "application/javascript";
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
// Configure Web API for Self-Host (정적 파일 후에 설정)
|
||||
HttpConfiguration config = new HttpConfiguration();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<meta name="version" content="v2.0-20250127">
|
||||
<title>근태현황 대시보드</title>
|
||||
<title>근태현황 대시보드*</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
@@ -218,105 +218,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 출근 대상자 모달 -->
|
||||
<div id="presentUserModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
<div class="glass-effect rounded-2xl w-full max-w-4xl max-h-[80vh] overflow-hidden animate-slide-up">
|
||||
<!-- 모달 헤더 -->
|
||||
<div class="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 class="text-xl font-semibold text-white flex items-center">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
금일 출근 대상자 목록
|
||||
</h2>
|
||||
<button onclick="hidePresentUserModal()" class="text-white/70 hover:text-white transition-colors">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 모달 내용 -->
|
||||
<div class="overflow-x-auto max-h-[60vh] custom-scrollbar">
|
||||
<table class="w-full">
|
||||
<thead class="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">사번</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">이름</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">공정</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">직급</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">상태</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">이메일</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="presentUserTable" class="divide-y divide-white/10">
|
||||
<!-- 데이터가 여기에 표시됩니다 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 모달 푸터 -->
|
||||
<div class="px-6 py-4 border-t border-white/10 flex justify-between items-center">
|
||||
<p class="text-white/70 text-sm">총 <span id="presentUserCount">0</span>명</p>
|
||||
<button onclick="hidePresentUserModal()" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 휴가요청 모달 -->
|
||||
<div id="holidayRequestModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
<div class="glass-effect rounded-2xl w-full max-w-6xl max-h-[80vh] overflow-hidden animate-slide-up">
|
||||
<!-- 모달 헤더 -->
|
||||
<div class="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 class="text-xl font-semibold text-white flex items-center">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
휴가 신청 목록
|
||||
</h2>
|
||||
<button onclick="hideHolidayRequestModal()" class="text-white/70 hover:text-white transition-colors">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 모달 내용 -->
|
||||
<div class="overflow-x-auto max-h-[60vh] custom-scrollbar">
|
||||
<table class="w-full">
|
||||
<thead class="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">사번</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">이름</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">항목</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">일자</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">요청일</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">요청시간</th>
|
||||
<th class="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">비고</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="holidayRequestTable" class="divide-y divide-white/10">
|
||||
<!-- 데이터가 여기에 표시됩니다 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 모달 푸터 -->
|
||||
<div class="px-6 py-4 border-t border-white/10 flex justify-between items-center">
|
||||
<p class="text-white/70 text-sm">총 <span id="holidayRequestCount">0</span>건</p>
|
||||
<button onclick="hideHolidayRequestModal()" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 구매NR 모달 -->
|
||||
<div id="purchaseNRModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
// CommonApp.jsx - React Common Code Management Component for GroupWare
|
||||
const { useState, useEffect, useRef } = React;
|
||||
|
||||
const CommonApp = () => {
|
||||
// 상태 관리
|
||||
const [groupData, setGroupData] = useState([]);
|
||||
const [currentData, setCurrentData] = useState([]);
|
||||
const [selectedGroupCode, setSelectedGroupCode] = useState(null);
|
||||
const [selectedGroupName, setSelectedGroupName] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [deleteTargetIdx, setDeleteTargetIdx] = useState(null);
|
||||
const [editMode, setEditMode] = useState('add');
|
||||
|
||||
// 편집 폼 데이터
|
||||
const [editData, setEditData] = useState({
|
||||
idx: '',
|
||||
grp: '',
|
||||
code: '',
|
||||
svalue: '',
|
||||
ivalue: '',
|
||||
fvalue: '',
|
||||
svalue2: '',
|
||||
memo: ''
|
||||
});
|
||||
|
||||
// 페이지 로드시 초기 데이터 로드
|
||||
useEffect(() => {
|
||||
loadGroups();
|
||||
}, []);
|
||||
|
||||
// API 호출 함수들
|
||||
const loadGroups = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:7979/Common/GetGroups');
|
||||
const data = await response.json();
|
||||
setGroupData(data || []);
|
||||
} catch (error) {
|
||||
console.error('그룹 데이터 로드 중 오류 발생:', error);
|
||||
showNotification('그룹 데이터 로드 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const loadDataByGroup = async (grp) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
let url = 'http://127.0.0.1:7979/Common/GetList';
|
||||
if (grp) {
|
||||
url += '?grp=' + encodeURIComponent(grp);
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
setCurrentData(data || []);
|
||||
} catch (error) {
|
||||
console.error('데이터 로드 중 오류 발생:', error);
|
||||
showNotification('데이터 로드 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const saveData = async () => {
|
||||
try {
|
||||
const data = {
|
||||
idx: parseInt(editData.idx) || 0,
|
||||
grp: editData.grp,
|
||||
code: editData.code,
|
||||
svalue: editData.svalue,
|
||||
ivalue: parseInt(editData.ivalue) || 0,
|
||||
fvalue: parseFloat(editData.fvalue) || 0.0,
|
||||
svalue2: editData.svalue2,
|
||||
memo: editData.memo
|
||||
};
|
||||
|
||||
setLoading(true);
|
||||
const response = await fetch('http://127.0.0.1:7979/Common/Save', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.Success) {
|
||||
showNotification(result.Message, 'success');
|
||||
setShowEditModal(false);
|
||||
if (selectedGroupCode) {
|
||||
loadDataByGroup(selectedGroupCode);
|
||||
}
|
||||
} else {
|
||||
showNotification(result.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('저장 중 오류 발생:', error);
|
||||
showNotification('저장 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItem = async () => {
|
||||
if (!deleteTargetIdx) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch('http://127.0.0.1:7979/Common/Delete', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ idx: deleteTargetIdx })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
showNotification(data.Message, 'success');
|
||||
setShowDeleteModal(false);
|
||||
if (selectedGroupCode) {
|
||||
loadDataByGroup(selectedGroupCode);
|
||||
}
|
||||
} else {
|
||||
showNotification(data.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('삭제 중 오류 발생:', error);
|
||||
showNotification('삭제 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setDeleteTargetIdx(null);
|
||||
}
|
||||
};
|
||||
|
||||
// 이벤트 핸들러들
|
||||
const selectGroup = (code, name) => {
|
||||
setSelectedGroupCode(code);
|
||||
setSelectedGroupName(name);
|
||||
loadDataByGroup(code);
|
||||
};
|
||||
|
||||
const openAddModal = () => {
|
||||
if (!selectedGroupCode) {
|
||||
showNotification('먼저 코드그룹을 선택하세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
setEditMode('add');
|
||||
setEditData({
|
||||
idx: '',
|
||||
grp: selectedGroupCode,
|
||||
code: '',
|
||||
svalue: '',
|
||||
ivalue: '',
|
||||
fvalue: '',
|
||||
svalue2: '',
|
||||
memo: ''
|
||||
});
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
const openEditModal = (item) => {
|
||||
setEditMode('edit');
|
||||
setEditData({
|
||||
idx: item.idx,
|
||||
grp: item.grp || '',
|
||||
code: item.code || '',
|
||||
svalue: item.svalue || '',
|
||||
ivalue: item.ivalue || '',
|
||||
fvalue: item.fvalue || '',
|
||||
svalue2: item.svalue2 || '',
|
||||
memo: item.memo || ''
|
||||
});
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
const openDeleteModal = (idx) => {
|
||||
setDeleteTargetIdx(idx);
|
||||
setShowDeleteModal(true);
|
||||
setShowEditModal(false);
|
||||
};
|
||||
|
||||
const closeModals = () => {
|
||||
setShowEditModal(false);
|
||||
setShowDeleteModal(false);
|
||||
setDeleteTargetIdx(null);
|
||||
};
|
||||
|
||||
const handleInputChange = (field, value) => {
|
||||
setEditData(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
const showNotification = (message, type = 'info') => {
|
||||
// 기존 알림 제거
|
||||
const existing = document.querySelectorAll('.notification-toast');
|
||||
existing.forEach(el => el.remove());
|
||||
|
||||
const colors = {
|
||||
info: 'bg-blue-500/90',
|
||||
success: 'bg-green-500/90',
|
||||
warning: 'bg-yellow-500/90',
|
||||
error: 'bg-red-500/90'
|
||||
};
|
||||
|
||||
const icons = {
|
||||
info: '🔵',
|
||||
success: '✅',
|
||||
warning: '⚠️',
|
||||
error: '❌'
|
||||
};
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `notification-toast fixed top-4 right-4 ${colors[type]} backdrop-blur-sm text-white px-4 py-3 rounded-lg z-50 shadow-lg border border-white/20`;
|
||||
notification.innerHTML = `<div class="flex items-center"><span class="mr-2">${icons[type]}</span>${message}</div>`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// 키보드 이벤트
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
closeModals();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
{/* Navigation Component */}
|
||||
<CommonNavigation currentPage="common" />
|
||||
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 2열 구조 메인 컨테이너 */}
|
||||
<div className="flex gap-6 h-[calc(100vh-200px)]">
|
||||
{/* 좌측: 코드그룹 리스트 */}
|
||||
<div className="w-80">
|
||||
<div className="glass-effect rounded-2xl h-full card-hover animate-slide-up flex flex-col">
|
||||
<div className="p-4 border-b border-white/10">
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11H5m14-7l-7 7-7-7M19 21l-7-7-7 7"></path>
|
||||
</svg>
|
||||
코드그룹 목록
|
||||
</h3>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar p-2">
|
||||
<div className="space-y-1">
|
||||
{groupData.length === 0 ? (
|
||||
<div className="text-white/70 text-center py-4">그룹 데이터가 없습니다.</div>
|
||||
) : (
|
||||
groupData.map(group => (
|
||||
<div
|
||||
key={group.code}
|
||||
className={`cursor-pointer p-3 rounded-lg border border-white/20 hover:bg-white/10 transition-all ${
|
||||
selectedGroupCode === group.code ? 'bg-white/20' : ''
|
||||
}`}
|
||||
onClick={() => selectGroup(group.code, group.memo)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<div className="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center mr-3">
|
||||
<span className="text-white text-sm font-medium">{group.code}</span>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="text-white font-medium">{group.memo}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 상세 데이터 */}
|
||||
<div className="flex-1">
|
||||
<div className="glass-effect rounded-2xl h-full card-hover animate-slide-up flex flex-col">
|
||||
{/* 상단 헤더 */}
|
||||
<div className="p-4 border-b border-white/10 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<span>
|
||||
{selectedGroupCode ? `${selectedGroupCode} - ${selectedGroupName}` : '코드그룹을 선택하세요'}
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-white/70 text-sm mt-1">
|
||||
총 <span className="text-white font-medium">{currentData.length}</span>건
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={openAddModal}
|
||||
className="bg-white/20 hover:bg-white/30 backdrop-blur-sm text-white px-4 py-2 rounded-lg transition-all border border-white/30 flex items-center text-sm"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
추가
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 데이터 테이블 */}
|
||||
<div className="flex-1 overflow-x-auto overflow-y-auto custom-scrollbar">
|
||||
<table className="w-full">
|
||||
<thead className="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
<th className="w-24 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">코드</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">비고</th>
|
||||
<th className="w-32 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값(문자열)</th>
|
||||
<th className="w-20 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값(숫자)</th>
|
||||
<th className="w-20 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값(실수)</th>
|
||||
<th className="w-24 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값2</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{currentData.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="6" className="px-4 py-8 text-center text-white/70">
|
||||
<svg className="w-12 h-12 mx-auto mb-2 text-white/30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
{selectedGroupCode ? '데이터가 없습니다.' : '좌측에서 코드그룹을 선택하세요'}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
currentData.map(item => (
|
||||
<tr
|
||||
key={item.idx}
|
||||
className="hover:bg-white/5 transition-colors cursor-pointer"
|
||||
onClick={() => openEditModal(item)}
|
||||
>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.code || '-'}</td>
|
||||
<td className="px-4 py-4 text-sm text-white">{item.memo || '-'}</td>
|
||||
<td className="px-4 py-4 text-sm text-white max-w-32 truncate" title={item.svalue || '-'}>
|
||||
{item.svalue || '-'}
|
||||
</td>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.ivalue || '0'}</td>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.fvalue || '0.0'}</td>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.svalue2 || '-'}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 로딩 인디케이터 */}
|
||||
{loading && (
|
||||
<div className="fixed top-4 right-4 bg-white/20 backdrop-blur-sm rounded-full px-4 py-2 text-white text-sm z-40">
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||
데이터 로딩 중...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 추가/편집 모달 */}
|
||||
{showEditModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-2xl animate-slide-up">
|
||||
{/* 모달 헤더 */}
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white">
|
||||
{editMode === 'add' ? '공용코드 추가' : '공용코드 편집'}
|
||||
</h2>
|
||||
<button
|
||||
onClick={closeModals}
|
||||
className="text-white/70 hover:text-white transition-colors"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 모달 내용 */}
|
||||
<div className="p-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">코드그룹 *</label>
|
||||
<select
|
||||
value={editData.grp}
|
||||
onChange={(e) => handleInputChange('grp', e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
>
|
||||
<option value="" className="bg-gray-800 text-white">선택하세요</option>
|
||||
{groupData.map(group => (
|
||||
<option key={group.code} value={group.code} className="bg-gray-800 text-white">
|
||||
{group.code}-{group.memo}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">코드 *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.code}
|
||||
onChange={(e) => handleInputChange('code', e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="코드를 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값(문자열)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.svalue}
|
||||
onChange={(e) => handleInputChange('svalue', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="문자열 값"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값(숫자)</label>
|
||||
<input
|
||||
type="number"
|
||||
value={editData.ivalue}
|
||||
onChange={(e) => handleInputChange('ivalue', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="숫자 값"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값(실수)</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
value={editData.fvalue}
|
||||
onChange={(e) => handleInputChange('fvalue', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="실수 값"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값2</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.svalue2}
|
||||
onChange={(e) => handleInputChange('svalue2', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="추가 문자열 값"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">비고</label>
|
||||
<textarea
|
||||
value={editData.memo}
|
||||
onChange={(e) => handleInputChange('memo', e.target.value)}
|
||||
rows="3"
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="비고사항을 입력하세요"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 모달 푸터 */}
|
||||
<div className="px-6 py-4 border-t border-white/10 flex justify-between">
|
||||
{editMode === 'edit' && (
|
||||
<button
|
||||
onClick={() => openDeleteModal(editData.idx)}
|
||||
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg transition-colors flex items-center"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
삭제
|
||||
</button>
|
||||
)}
|
||||
<div className="flex gap-2 ml-auto">
|
||||
<button
|
||||
onClick={closeModals}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={saveData}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 삭제 확인 모달 */}
|
||||
{showDeleteModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-md animate-slide-up">
|
||||
<div className="p-6">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="w-12 h-12 bg-red-100/20 rounded-full flex items-center justify-center mr-4">
|
||||
<svg className="w-6 h-6 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 18.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-medium text-white">삭제 확인</h3>
|
||||
<p className="text-sm text-white/70">이 작업은 되돌릴 수 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-white/80 mb-6">
|
||||
선택한 공용코드를 삭제하시겠습니까?<br/>
|
||||
<span className="text-sm text-white/60">이 작업은 되돌릴 수 없습니다.</span>
|
||||
</p>
|
||||
<div className="flex justify-end gap-2">
|
||||
<button
|
||||
onClick={closeModals}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={deleteItem}
|
||||
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
삭제
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,590 +0,0 @@
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function CommonCode() {
|
||||
// 상태 관리
|
||||
const [currentData, setCurrentData] = useState([]);
|
||||
const [groupData, setGroupData] = useState([]);
|
||||
const [selectedGroupCode, setSelectedGroupCode] = useState(null);
|
||||
const [selectedGroupName, setSelectedGroupName] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [deleteTargetIdx, setDeleteTargetIdx] = useState(null);
|
||||
const [editData, setEditData] = useState({
|
||||
idx: '',
|
||||
grp: '',
|
||||
code: '',
|
||||
svalue: '',
|
||||
ivalue: '',
|
||||
fvalue: '',
|
||||
svalue2: '',
|
||||
memo: ''
|
||||
});
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
|
||||
// 컴포넌트 마운트 시 초기 데이터 로드
|
||||
useEffect(() => {
|
||||
loadGroups();
|
||||
}, []);
|
||||
|
||||
// 코드그룹 목록 로드
|
||||
const loadGroups = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Common/GetGroups');
|
||||
const data = await response.json();
|
||||
setGroupData(data || []);
|
||||
} catch (error) {
|
||||
console.error('그룹 데이터 로드 중 오류 발생:', error);
|
||||
showNotification('그룹 데이터 로드 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 그룹 선택 처리
|
||||
const selectGroup = async (code, name) => {
|
||||
setSelectedGroupCode(code);
|
||||
setSelectedGroupName(name);
|
||||
await loadDataByGroup(code);
|
||||
};
|
||||
|
||||
// 특정 그룹의 데이터 로드
|
||||
const loadDataByGroup = async (grp) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
let url = '/Common/GetList';
|
||||
if (grp) {
|
||||
url += '?grp=' + encodeURIComponent(grp);
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
setCurrentData(data || []);
|
||||
} catch (error) {
|
||||
console.error('데이터 로드 중 오류 발생:', error);
|
||||
showNotification('데이터 로드 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 추가 모달 표시
|
||||
const showAddModal = () => {
|
||||
if (!selectedGroupCode) {
|
||||
showNotification('먼저 코드그룹을 선택하세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsEditMode(false);
|
||||
setEditData({
|
||||
idx: '',
|
||||
grp: selectedGroupCode,
|
||||
code: '',
|
||||
svalue: '',
|
||||
ivalue: '',
|
||||
fvalue: '',
|
||||
svalue2: '',
|
||||
memo: ''
|
||||
});
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
// 편집 모달 표시
|
||||
const editItem = (idx) => {
|
||||
const item = currentData.find(x => x.idx === idx);
|
||||
if (!item) return;
|
||||
|
||||
setIsEditMode(true);
|
||||
setEditData({
|
||||
idx: item.idx,
|
||||
grp: item.grp || '',
|
||||
code: item.code || '',
|
||||
svalue: item.svalue || '',
|
||||
ivalue: item.ivalue || '',
|
||||
fvalue: item.fvalue || '',
|
||||
svalue2: item.svalue2 || '',
|
||||
memo: item.memo || ''
|
||||
});
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
// 데이터 저장
|
||||
const saveData = async () => {
|
||||
const form = document.getElementById('editForm');
|
||||
if (!form.checkValidity()) {
|
||||
form.reportValidity();
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
idx: parseInt(editData.idx) || 0,
|
||||
grp: editData.grp,
|
||||
code: editData.code,
|
||||
svalue: editData.svalue,
|
||||
ivalue: parseInt(editData.ivalue) || 0,
|
||||
fvalue: parseFloat(editData.fvalue) || 0.0,
|
||||
svalue2: editData.svalue2,
|
||||
memo: editData.memo
|
||||
};
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Common/Save', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.Success) {
|
||||
showNotification(result.Message, 'success');
|
||||
setShowEditModal(false);
|
||||
if (selectedGroupCode) {
|
||||
await loadDataByGroup(selectedGroupCode);
|
||||
}
|
||||
} else {
|
||||
showNotification(result.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('저장 중 오류 발생:', error);
|
||||
showNotification('저장 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 확인
|
||||
const confirmDelete = async () => {
|
||||
if (!deleteTargetIdx) return;
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Common/Delete', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ idx: deleteTargetIdx })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (data.Success) {
|
||||
showNotification(data.Message, 'success');
|
||||
setShowDeleteModal(false);
|
||||
setDeleteTargetIdx(null);
|
||||
if (selectedGroupCode) {
|
||||
await loadDataByGroup(selectedGroupCode);
|
||||
}
|
||||
} else {
|
||||
showNotification(data.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('삭제 중 오류 발생:', error);
|
||||
showNotification('삭제 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 요청
|
||||
const deleteCurrentItem = () => {
|
||||
if (!editData.idx) {
|
||||
showNotification('삭제할 항목이 없습니다.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
setDeleteTargetIdx(parseInt(editData.idx));
|
||||
setShowEditModal(false);
|
||||
setShowDeleteModal(true);
|
||||
};
|
||||
|
||||
// 알림 표시 함수
|
||||
const showNotification = (message, type = 'info') => {
|
||||
const colors = {
|
||||
info: 'bg-blue-500/90 backdrop-blur-sm',
|
||||
success: 'bg-green-500/90 backdrop-blur-sm',
|
||||
warning: 'bg-yellow-500/90 backdrop-blur-sm',
|
||||
error: 'bg-red-500/90 backdrop-blur-sm'
|
||||
};
|
||||
|
||||
const icons = {
|
||||
info: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
),
|
||||
success: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
),
|
||||
warning: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 18.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
),
|
||||
error: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
)
|
||||
};
|
||||
|
||||
// React에서는 실제 DOM 조작 대신 Toast 라이브러리나 상태로 관리하는 것이 좋습니다
|
||||
// 여기서는 기존 방식을 유지하되 React 컴포넌트 스타일로 구현
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`;
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
${type === 'info' ? '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>' : ''}
|
||||
${type === 'success' ? '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>' : ''}
|
||||
${type === 'warning' ? '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 18.5c-.77.833.192 2.5 1.732 2.5z"></path></svg>' : ''}
|
||||
${type === 'error' ? '<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>' : ''}
|
||||
<span class="ml-2">${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(0)';
|
||||
notification.style.opacity = '1';
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// 키보드 이벤트 핸들러
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
setShowEditModal(false);
|
||||
setShowDeleteModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, []);
|
||||
|
||||
// 입력 필드 변경 핸들러
|
||||
const handleInputChange = (field, value) => {
|
||||
setEditData(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 2열 구조 메인 컨테이너 */}
|
||||
<div className="flex gap-6 h-[calc(100vh-200px)]">
|
||||
{/* 좌측: 코드그룹 리스트 */}
|
||||
<div className="w-80">
|
||||
<div className="glass-effect rounded-2xl h-full card-hover animate-slide-up flex flex-col">
|
||||
<div className="p-4 border-b border-white/10">
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11H5m14-7l-7 7-7-7M19 21l-7-7-7 7"></path>
|
||||
</svg>
|
||||
코드그룹 목록
|
||||
</h3>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto custom-scrollbar p-2">
|
||||
<div className="space-y-1">
|
||||
{groupData.length === 0 ? (
|
||||
<div className="text-white/70 text-center py-4">그룹 데이터가 없습니다.</div>
|
||||
) : (
|
||||
groupData.map(group => (
|
||||
<div
|
||||
key={group.code}
|
||||
className={`group-item cursor-pointer p-3 rounded-lg border border-white/20 hover:bg-white/10 transition-all ${
|
||||
selectedGroupCode === group.code ? 'bg-white/20' : ''
|
||||
}`}
|
||||
onClick={() => selectGroup(group.code, group.memo)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<div className="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center mr-3">
|
||||
<span className="text-white text-sm font-medium">{group.code}</span>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="text-white font-medium">{group.memo}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 상세 데이터 */}
|
||||
<div className="flex-1">
|
||||
<div className="glass-effect rounded-2xl h-full card-hover animate-slide-up flex flex-col">
|
||||
{/* 상단 헤더 */}
|
||||
<div className="p-4 border-b border-white/10 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<span>{selectedGroupCode ? `${selectedGroupCode} - ${selectedGroupName}` : '코드그룹을 선택하세요'}</span>
|
||||
</h3>
|
||||
<p className="text-white/70 text-sm mt-1">총 <span className="text-white font-medium">{currentData.length}</span>건</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={showAddModal}
|
||||
className="bg-white/20 hover:bg-white/30 backdrop-blur-sm text-white px-4 py-2 rounded-lg transition-all border border-white/30 flex items-center text-sm"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
추가
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 데이터 테이블 */}
|
||||
<div className="flex-1 overflow-x-auto overflow-y-auto custom-scrollbar">
|
||||
<table className="w-full">
|
||||
<thead className="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
<th className="w-24 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">코드</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">비고</th>
|
||||
<th className="w-32 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값(문자열)</th>
|
||||
<th className="w-20 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값(숫자)</th>
|
||||
<th className="w-20 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값(실수)</th>
|
||||
<th className="w-24 px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">값2</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{currentData.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="6" className="px-4 py-8 text-center text-white/70">
|
||||
<svg className="w-12 h-12 mx-auto mb-2 text-white/30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
{selectedGroupCode ? '데이터가 없습니다.' : '좌측에서 코드그룹을 선택하세요'}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
currentData.map(item => (
|
||||
<tr
|
||||
key={item.idx}
|
||||
className="hover:bg-white/5 transition-colors cursor-pointer"
|
||||
onClick={() => editItem(item.idx)}
|
||||
>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.code || '-'}</td>
|
||||
<td className="px-4 py-4 text-sm text-white">{item.memo || '-'}</td>
|
||||
<td className="px-4 py-4 text-sm text-white svalue-cell" title={item.svalue || '-'}>{item.svalue || '-'}</td>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.ivalue || '0'}</td>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.fvalue || '0.0'}</td>
|
||||
<td className="px-4 py-4 whitespace-nowrap text-sm text-white">{item.svalue2 || '-'}</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 로딩 인디케이터 */}
|
||||
{isLoading && (
|
||||
<div className="fixed top-4 right-4 bg-white/20 backdrop-blur-sm rounded-full px-4 py-2 text-white text-sm">
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||
데이터 로딩 중...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 추가/편집 모달 */}
|
||||
{showEditModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-2xl animate-slide-up">
|
||||
{/* 모달 헤더 */}
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white">
|
||||
{isEditMode ? '공용코드 편집' : '공용코드 추가'}
|
||||
</h2>
|
||||
<button
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="text-white/70 hover:text-white transition-colors"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 모달 내용 */}
|
||||
<form id="editForm" className="p-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">코드그룹 *</label>
|
||||
<select
|
||||
value={editData.grp}
|
||||
onChange={(e) => handleInputChange('grp', e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
>
|
||||
<option value="" className="bg-gray-800 text-white">선택하세요</option>
|
||||
{groupData.map(group => (
|
||||
<option key={group.code} value={group.code} className="bg-gray-800 text-white">
|
||||
{group.code}-{group.memo}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">코드 *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.code}
|
||||
onChange={(e) => handleInputChange('code', e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="코드를 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값(문자열)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.svalue}
|
||||
onChange={(e) => handleInputChange('svalue', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="문자열 값"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값(숫자)</label>
|
||||
<input
|
||||
type="number"
|
||||
value={editData.ivalue}
|
||||
onChange={(e) => handleInputChange('ivalue', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="숫자 값"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값(실수)</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
value={editData.fvalue}
|
||||
onChange={(e) => handleInputChange('fvalue', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="실수 값"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">값2</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.svalue2}
|
||||
onChange={(e) => handleInputChange('svalue2', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="추가 문자열 값"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<label className="block text-sm font-medium text-white/70 mb-2">비고</label>
|
||||
<textarea
|
||||
value={editData.memo}
|
||||
onChange={(e) => handleInputChange('memo', e.target.value)}
|
||||
rows="3"
|
||||
className="w-full px-3 py-2 bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="비고사항을 입력하세요"
|
||||
></textarea>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* 모달 푸터 */}
|
||||
<div className="px-6 py-4 border-t border-white/10 flex justify-between">
|
||||
<button
|
||||
onClick={deleteCurrentItem}
|
||||
disabled={!isEditMode}
|
||||
className={`bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg transition-colors flex items-center ${
|
||||
!isEditMode ? 'opacity-50 cursor-not-allowed' : ''
|
||||
}`}
|
||||
>
|
||||
<svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
삭제
|
||||
</button>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={saveData}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 삭제 확인 모달 */}
|
||||
{showDeleteModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-md animate-slide-up">
|
||||
<div className="p-6">
|
||||
<div className="flex items-center mb-4">
|
||||
<div className="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center mr-4">
|
||||
<svg className="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.5 0L4.268 18.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-medium text-gray-900">삭제 확인</h3>
|
||||
<p className="text-sm text-gray-500">이 작업은 되돌릴 수 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-gray-700 mb-6">
|
||||
선택한 공용코드를 삭제하시겠습니까?<br />
|
||||
<span className="text-sm text-gray-500">이 작업은 되돌릴 수 없습니다.</span>
|
||||
</p>
|
||||
<div className="flex justify-end gap-2">
|
||||
<button
|
||||
onClick={() => { setShowDeleteModal(false); setDeleteTargetIdx(null); }}
|
||||
className="bg-gray-300 hover:bg-gray-400 text-gray-700 px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
onClick={confirmDelete}
|
||||
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
삭제
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
// CommonNavigation.jsx - React Navigation Component for GroupWare
|
||||
const CommonNavigation = ({ currentPage = 'dashboard' }) => {
|
||||
const [menuItems, setMenuItems] = useState([]);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const [currentUser, setCurrentUser] = useState('사용자');
|
||||
|
||||
// 기본 메뉴 아이템 - React 경로 사용
|
||||
const defaultMenuItems = [
|
||||
{
|
||||
key: 'dashboard',
|
||||
title: '대시보드',
|
||||
url: '/react/dashboard',
|
||||
icon: 'M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z M8 5a2 2 0 012-2h4a2 2 0 012 2v2H8V5z',
|
||||
isVisible: true,
|
||||
sortOrder: 1
|
||||
},
|
||||
{
|
||||
key: 'common',
|
||||
title: '공용코드',
|
||||
url: '/react/common',
|
||||
icon: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',
|
||||
isVisible: true,
|
||||
sortOrder: 2
|
||||
},
|
||||
{
|
||||
key: 'jobreport',
|
||||
title: '업무일지',
|
||||
url: '/react/jobreport',
|
||||
icon: 'M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2',
|
||||
isVisible: true,
|
||||
sortOrder: 3
|
||||
},
|
||||
{
|
||||
key: 'kuntae',
|
||||
title: '근태관리',
|
||||
url: '/react/kuntae',
|
||||
icon: 'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z',
|
||||
isVisible: true,
|
||||
sortOrder: 4
|
||||
},
|
||||
{
|
||||
key: 'todo',
|
||||
title: '할일관리',
|
||||
url: '/react/todo',
|
||||
icon: 'M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2M12 12l2 2 4-4',
|
||||
isVisible: true,
|
||||
sortOrder: 5
|
||||
},
|
||||
{
|
||||
key: 'project',
|
||||
title: '프로젝트',
|
||||
url: '/react/project',
|
||||
icon: 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10',
|
||||
isVisible: true,
|
||||
sortOrder: 6
|
||||
},
|
||||
{
|
||||
key: 'purchase',
|
||||
title: '구매관리',
|
||||
url: '/Purchase/',
|
||||
icon: 'M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z',
|
||||
isVisible: true,
|
||||
sortOrder: 7
|
||||
},
|
||||
{
|
||||
key: 'customer',
|
||||
title: '고객관리',
|
||||
url: '/Customer/',
|
||||
icon: 'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z',
|
||||
isVisible: true,
|
||||
sortOrder: 8
|
||||
}
|
||||
];
|
||||
|
||||
// 메뉴 아이템 로드 - defaultMenuItems 사용 (React 경로)
|
||||
useEffect(() => {
|
||||
setMenuItems(defaultMenuItems);
|
||||
}, []);
|
||||
|
||||
// 보이는 메뉴 아이템만 정렬해서 반환
|
||||
const visibleItems = menuItems
|
||||
.filter(item => item.isVisible)
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder);
|
||||
|
||||
return (
|
||||
<nav className="glass-effect border-b border-white/10 relative z-40">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="flex items-center justify-between h-16">
|
||||
{/* 로고 및 브랜드 */}
|
||||
<div className="flex items-center space-x-8">
|
||||
<div className="flex items-center space-x-2">
|
||||
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z M8 5a2 2 0 012-2h4a2 2 0 012 2v2H8V5z"></path>
|
||||
</svg>
|
||||
<span className="text-xl font-bold text-white">GroupWare</span>
|
||||
</div>
|
||||
|
||||
{/* 데스크톱 메뉴 */}
|
||||
<nav className="hidden md:flex space-x-1">
|
||||
{visibleItems.map(item => (
|
||||
<a
|
||||
key={item.key}
|
||||
href={item.url}
|
||||
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
currentPage === item.key
|
||||
? 'bg-white/20 text-white'
|
||||
: 'text-white/60 hover:text-white hover:bg-white/10'
|
||||
}`}
|
||||
>
|
||||
<svg className="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d={item.icon}></path>
|
||||
</svg>
|
||||
{item.title}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* 우측 메뉴 */}
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="text-sm text-white/60">
|
||||
<span>{currentUser}</span>
|
||||
</div>
|
||||
|
||||
{/* 모바일 메뉴 버튼 */}
|
||||
<button
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
className="md:hidden text-white/60 hover:text-white focus:outline-none focus:text-white"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{mobileMenuOpen ? (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
) : (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 모바일 메뉴 */}
|
||||
{mobileMenuOpen && (
|
||||
<div className="md:hidden border-t border-white/10 py-2">
|
||||
{visibleItems.map(item => (
|
||||
<a
|
||||
key={item.key}
|
||||
href={item.url}
|
||||
className={`block px-3 py-2 text-sm font-medium transition-colors ${
|
||||
currentPage === item.key
|
||||
? 'bg-white/20 text-white'
|
||||
: 'text-white/60 hover:text-white hover:bg-white/10'
|
||||
}`}
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
<svg className="w-4 h-4 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d={item.icon}></path>
|
||||
</svg>
|
||||
{item.title}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
@@ -1,669 +0,0 @@
|
||||
// DashboardApp.jsx - React Dashboard Component for GroupWare
|
||||
const { useState, useEffect, useRef } = React;
|
||||
|
||||
function DashboardApp() {
|
||||
// 상태 관리
|
||||
const [dashboardData, setDashboardData] = useState({
|
||||
presentCount: 0,
|
||||
leaveCount: 0,
|
||||
leaveRequestCount: 0,
|
||||
purchaseCountNR: 0,
|
||||
purchaseCountCR: 0
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [lastUpdated, setLastUpdated] = useState('');
|
||||
const [modals, setModals] = useState({
|
||||
presentUsers: false,
|
||||
holidayUsers: false,
|
||||
holidayRequest: false,
|
||||
purchaseNR: false,
|
||||
purchaseCR: false
|
||||
});
|
||||
|
||||
const [modalData, setModalData] = useState({
|
||||
presentUsers: [],
|
||||
holidayUsers: [],
|
||||
holidayRequests: [],
|
||||
purchaseNR: [],
|
||||
purchaseCR: []
|
||||
});
|
||||
|
||||
const [todoList, setTodoList] = useState([]);
|
||||
|
||||
// 모달 제어 함수
|
||||
const showModal = (modalName) => {
|
||||
setModals(prev => ({ ...prev, [modalName]: true }));
|
||||
loadModalData(modalName);
|
||||
};
|
||||
|
||||
const hideModal = (modalName) => {
|
||||
setModals(prev => ({ ...prev, [modalName]: false }));
|
||||
};
|
||||
|
||||
// Dashboard 데이터 로드
|
||||
const loadDashboardData = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
// 실제 DashBoardController API 호출
|
||||
const [
|
||||
currentUserResponse,
|
||||
leaveCountResponse,
|
||||
holyRequestResponse,
|
||||
purchaseWaitResponse
|
||||
] = await Promise.all([
|
||||
fetch('http://127.0.0.1:7979/DashBoard/GetCurrentUserCount'),
|
||||
fetch('http://127.0.0.1:7979/DashBoard/TodayCountH'),
|
||||
fetch('http://127.0.0.1:7979/DashBoard/GetHolydayRequestCount'),
|
||||
fetch('http://127.0.0.1:7979/DashBoard/GetPurchaseWaitCount')
|
||||
]);
|
||||
|
||||
// 현재 근무자 수 (JSON 응답)
|
||||
const currentUserData = await currentUserResponse.json();
|
||||
const presentCount = currentUserData.Count || 0;
|
||||
|
||||
// 휴가자 수 (텍스트 응답)
|
||||
const leaveCountText = await leaveCountResponse.text();
|
||||
const leaveCount = parseInt(leaveCountText.replace(/"/g, ''), 10) || 0;
|
||||
|
||||
// 휴가 요청 수 (JSON 응답)
|
||||
const holyRequestData = await holyRequestResponse.json();
|
||||
const leaveRequestCount = holyRequestData.HOLY || 0;
|
||||
|
||||
// 구매 대기 수 (JSON 응답)
|
||||
const purchaseWaitData = await purchaseWaitResponse.json();
|
||||
const purchaseCountNR = purchaseWaitData.NR || 0;
|
||||
const purchaseCountCR = purchaseWaitData.CR || 0;
|
||||
|
||||
setDashboardData({
|
||||
presentCount,
|
||||
leaveCount,
|
||||
leaveRequestCount,
|
||||
purchaseCountNR,
|
||||
purchaseCountCR
|
||||
});
|
||||
|
||||
setLastUpdated(new Date().toLocaleString('ko-KR'));
|
||||
} catch (error) {
|
||||
console.error('대시보드 데이터 로드 실패:', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 모달 데이터 로드
|
||||
const loadModalData = async (modalName) => {
|
||||
try {
|
||||
let endpoint = '';
|
||||
switch (modalName) {
|
||||
case 'presentUsers':
|
||||
endpoint = 'http://127.0.0.1:7979/DashBoard/GetPresentUserList';
|
||||
break;
|
||||
case 'holidayUsers':
|
||||
endpoint = 'http://127.0.0.1:7979/DashBoard/GetholyUser';
|
||||
break;
|
||||
case 'holidayRequest':
|
||||
endpoint = 'http://127.0.0.1:7979/DashBoard/GetholyRequestUser';
|
||||
break;
|
||||
case 'purchaseNR':
|
||||
endpoint = 'http://127.0.0.1:7979/DashBoard/GetPurchaseNRList';
|
||||
break;
|
||||
case 'purchaseCR':
|
||||
endpoint = 'http://127.0.0.1:7979/DashBoard/GetPurchaseCRList';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(endpoint);
|
||||
const data = await response.json();
|
||||
|
||||
setModalData(prev => ({
|
||||
...prev,
|
||||
[modalName]: Array.isArray(data) ? data : []
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error(`모달 데이터 로드 실패 (${modalName}):`, error);
|
||||
setModalData(prev => ({
|
||||
...prev,
|
||||
[modalName]: []
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Todo 목록 로드
|
||||
const loadTodoList = async () => {
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:7979/Todo/GetUrgentTodos');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success && data.Data) {
|
||||
setTodoList(data.Data);
|
||||
} else {
|
||||
setTodoList([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Todo 목록 로드 실패:', error);
|
||||
setTodoList([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 자동 새로고침 (30초마다)
|
||||
useEffect(() => {
|
||||
loadDashboardData();
|
||||
loadModalData('holidayUsers'); // 휴가자 목록 자동 로드
|
||||
loadTodoList(); // Todo 목록 자동 로드
|
||||
|
||||
const interval = setInterval(() => {
|
||||
loadDashboardData();
|
||||
loadModalData('holidayUsers'); // 30초마다 휴가자 목록도 새로고침
|
||||
loadTodoList(); // 30초마다 Todo 목록도 새로고침
|
||||
}, 30000); // 30초
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// 통계 카드 컴포넌트
|
||||
const StatCard = ({ title, count, icon, color, onClick, isClickable = false }) => {
|
||||
return (
|
||||
<div
|
||||
className={`glass-effect rounded-2xl p-6 card-hover animate-slide-up ${isClickable ? 'cursor-pointer' : ''}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-white/70 text-sm font-medium">{title}</p>
|
||||
<p className="text-3xl font-bold text-white">
|
||||
{isLoading ? (
|
||||
<div className="animate-pulse bg-white/20 h-8 w-16 rounded"></div>
|
||||
) : count}
|
||||
</p>
|
||||
</div>
|
||||
<div className={`w-12 h-12 ${color}/20 rounded-full flex items-center justify-center`}>
|
||||
{icon}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 테이블 모달 컴포넌트
|
||||
const TableModal = ({ isOpen, onClose, title, headers, data, renderRow, maxWidth = 'max-w-4xl' }) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className={`glass-effect rounded-2xl w-full ${maxWidth} max-h-[80vh] overflow-hidden animate-slide-up`}>
|
||||
{/* 모달 헤더 */}
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
{title}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-white/70 hover:text-white transition-colors"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 모달 내용 */}
|
||||
<div className="overflow-x-auto max-h-[60vh] custom-scrollbar">
|
||||
<table className="w-full">
|
||||
<thead className="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
{headers.map((header, index) => (
|
||||
<th key={index} className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">
|
||||
{header}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{data.length > 0 ? (
|
||||
data.map((item, index) => renderRow(item, index))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={headers.length} className="px-6 py-8 text-center text-white/50">
|
||||
데이터가 없습니다.
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* 모달 푸터 */}
|
||||
<div className="px-6 py-4 border-t border-white/10 flex justify-between items-center">
|
||||
<p className="text-white/70 text-sm">
|
||||
총 <span className="font-medium">{data.length}</span>건
|
||||
</p>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 헤더 */}
|
||||
<div className="text-center mb-8 animate-fade-in">
|
||||
<h1 className="text-4xl font-bold mb-4">근태현황 대시보드</h1>
|
||||
<p className="text-white/70">실시간 근태 및 업무 현황을 확인하세요</p>
|
||||
{lastUpdated && (
|
||||
<p className="text-white/50 text-sm mt-2">마지막 업데이트: {lastUpdated}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 새로고침 버튼 */}
|
||||
<div className="flex justify-end mb-6">
|
||||
<button
|
||||
onClick={loadDashboardData}
|
||||
disabled={isLoading}
|
||||
className="glass-effect rounded-lg px-4 py-2 text-white hover:bg-white/10 transition-all duration-300 disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? (
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2 inline-block"></div>
|
||||
) : (
|
||||
<svg className="w-4 h-4 mr-2 inline-block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
)}
|
||||
새로고침
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 통계 카드 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mb-8">
|
||||
<StatCard
|
||||
title="출근(대상)"
|
||||
count={dashboardData.presentCount}
|
||||
isClickable={true}
|
||||
onClick={() => showModal('presentUsers')}
|
||||
color="bg-success-500"
|
||||
icon={
|
||||
<svg className="w-6 h-6 text-success-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
title="휴가"
|
||||
count={dashboardData.leaveCount}
|
||||
isClickable={true}
|
||||
onClick={() => showModal('holidayUsers')}
|
||||
color="bg-warning-500"
|
||||
icon={
|
||||
<svg className="w-6 h-6 text-warning-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
title="휴가요청"
|
||||
count={dashboardData.leaveRequestCount}
|
||||
isClickable={true}
|
||||
onClick={() => showModal('holidayRequest')}
|
||||
color="bg-primary-500"
|
||||
icon={
|
||||
<svg className="w-6 h-6 text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
title="구매요청(NR)"
|
||||
count={dashboardData.purchaseCountNR}
|
||||
isClickable={true}
|
||||
onClick={() => showModal('purchaseNR')}
|
||||
color="bg-danger-500"
|
||||
icon={
|
||||
<svg className="w-6 h-6 text-danger-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
title="구매요청(CR)"
|
||||
count={dashboardData.purchaseCountCR}
|
||||
isClickable={true}
|
||||
onClick={() => showModal('purchaseCR')}
|
||||
color="bg-purple-500"
|
||||
icon={
|
||||
<svg className="w-6 h-6 text-purple-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
|
||||
</svg>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 2칸 레이아웃: 좌측 휴가현황, 우측 할일 */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 animate-slide-up">
|
||||
{/* 좌측: 휴가/기타 현황 */}
|
||||
<div className="glass-effect rounded-2xl overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-white/10">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
</svg>
|
||||
휴가/기타 현황
|
||||
</h2>
|
||||
</div>
|
||||
<div className="overflow-x-auto max-h-[460px] custom-scrollbar">
|
||||
<table className="w-full">
|
||||
<thead className="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">이름</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">형태</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">종류</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">기간</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/70 uppercase tracking-wider">사유</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{modalData.holidayUsers.map((user, index) => {
|
||||
// 형태에 따른 색상 결정
|
||||
const typeColorClass = (user.type === '휴가') ? 'bg-green-500/20 text-green-300' : 'bg-warning-500/20 text-warning-300';
|
||||
|
||||
// 종류에 따른 색상 결정
|
||||
let cateColorClass = 'bg-warning-500/20 text-warning-300'; // 기본값
|
||||
if (user.cate === '휴가') {
|
||||
cateColorClass = 'bg-warning-500/20 text-warning-300'; // 노란색 계열
|
||||
} else if (user.cate === '파견') {
|
||||
cateColorClass = 'bg-purple-500/20 text-purple-300'; // 보라색 계열
|
||||
} else {
|
||||
cateColorClass = 'bg-warning-500/20 text-warning-300'; // 기타는 주황색 계열
|
||||
}
|
||||
|
||||
// 기간 표시 형식 개선
|
||||
let periodText = '';
|
||||
if (user.sdate && user.edate) {
|
||||
if (user.sdate === user.edate) {
|
||||
periodText = user.sdate;
|
||||
} else {
|
||||
periodText = `${user.sdate}~${user.edate}`;
|
||||
}
|
||||
} else {
|
||||
periodText = '-';
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={index} className="hover:bg-white/5">
|
||||
<td className="px-4 py-3 text-white text-sm font-medium">{user.name || '이름 없음'}</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${typeColorClass}`}>
|
||||
{user.type || 'N/A'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${cateColorClass}`}>
|
||||
{user.cate || '종류 없음'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-white text-sm">{periodText}</td>
|
||||
<td className="px-4 py-3 text-white/70 text-sm">{user.title || '사유 없음'}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
{modalData.holidayUsers.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan="5" className="px-4 py-8 text-center text-white/50">
|
||||
현재 휴가자가 없습니다
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 할일 */}
|
||||
<div className="glass-effect rounded-2xl overflow-hidden">
|
||||
<div className="px-6 py-4 border-b border-white/10">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center justify-between">
|
||||
<span className="flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
</svg>
|
||||
할일
|
||||
</span>
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
className="text-xs bg-primary-500/20 hover:bg-primary-500/30 text-primary-300 hover:text-primary-200 px-3 py-1 rounded-full transition-colors flex items-center"
|
||||
onClick={() => alert('할일 추가 기능은 준비 중입니다.')}
|
||||
>
|
||||
<svg className="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
할일추가
|
||||
</button>
|
||||
<button
|
||||
className="text-xs bg-white/20 hover:bg-white/30 px-3 py-1 rounded-full transition-colors"
|
||||
onClick={() => window.location.href = '/react/todo'}
|
||||
>
|
||||
전체보기
|
||||
</button>
|
||||
</div>
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="space-y-3 max-h-[384px] overflow-y-auto custom-scrollbar">
|
||||
{todoList.length > 0 ? (
|
||||
todoList.map((todo, index) => {
|
||||
const flagIcon = todo.flag ? '📌 ' : '';
|
||||
|
||||
// 상태별 클래스
|
||||
const getTodoStatusClass = (status) => {
|
||||
switch(status) {
|
||||
case '0': return 'bg-gray-500/20 text-gray-300';
|
||||
case '1': return 'bg-primary-500/20 text-primary-300';
|
||||
case '2': return 'bg-danger-500/20 text-danger-300';
|
||||
case '3': return 'bg-warning-500/20 text-warning-300';
|
||||
case '5': return 'bg-success-500/20 text-success-300';
|
||||
default: return 'bg-white/10 text-white/50';
|
||||
}
|
||||
};
|
||||
|
||||
const getTodoStatusText = (status) => {
|
||||
switch(status) {
|
||||
case '0': return '대기';
|
||||
case '1': return '진행';
|
||||
case '2': return '취소';
|
||||
case '3': return '보류';
|
||||
case '5': return '완료';
|
||||
default: return '대기';
|
||||
}
|
||||
};
|
||||
|
||||
const getTodoSeqnoClass = (seqno) => {
|
||||
switch(seqno) {
|
||||
case '0': return 'bg-gray-500/20 text-gray-300';
|
||||
case '1': return 'bg-success-500/20 text-success-300';
|
||||
case '2': return 'bg-warning-500/20 text-warning-300';
|
||||
case '3': return 'bg-danger-500/20 text-danger-300';
|
||||
default: return 'bg-white/10 text-white/50';
|
||||
}
|
||||
};
|
||||
|
||||
const getTodoSeqnoText = (seqno) => {
|
||||
switch(seqno) {
|
||||
case '0': return '낮음';
|
||||
case '1': return '보통';
|
||||
case '2': return '높음';
|
||||
case '3': return '긴급';
|
||||
default: return '보통';
|
||||
}
|
||||
};
|
||||
|
||||
const statusClass = getTodoStatusClass(todo.status);
|
||||
const statusText = getTodoStatusText(todo.status);
|
||||
const seqnoClass = getTodoSeqnoClass(todo.seqno);
|
||||
const seqnoText = getTodoSeqnoText(todo.seqno);
|
||||
|
||||
const expireText = todo.expire ? new Date(todo.expire).toLocaleDateString('ko-KR') : '';
|
||||
const isExpired = todo.expire && new Date(todo.expire) < new Date();
|
||||
const expireClass = isExpired ? 'text-danger-400' : 'text-white/60';
|
||||
|
||||
// 만료일이 지난 경우 배경을 적색계통으로 강조
|
||||
const expiredBgClass = isExpired ? 'bg-danger-600/30 border-danger-400/40 hover:bg-danger-600/40' : 'bg-white/10 hover:bg-white/15 border-white/20';
|
||||
|
||||
return (
|
||||
<div key={index} className={`${expiredBgClass} backdrop-blur-sm rounded-lg p-3 transition-colors cursor-pointer border`}
|
||||
onClick={() => alert('Todo 상세보기 기능은 준비 중입니다.')}>
|
||||
<div className="flex items-start justify-between mb-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<span className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${statusClass}`}>
|
||||
{statusText}
|
||||
</span>
|
||||
<span className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${seqnoClass}`}>
|
||||
{seqnoText}
|
||||
</span>
|
||||
</div>
|
||||
{expireText && (
|
||||
<span className={`text-xs ${expireClass}`}>
|
||||
{expireText}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-white text-sm font-medium mb-1">
|
||||
{flagIcon}{todo.title || '제목 없음'}
|
||||
</p>
|
||||
{todo.description && (
|
||||
<p className="text-white/70 text-xs mb-2 line-clamp-2">
|
||||
{todo.description}
|
||||
</p>
|
||||
)}
|
||||
{todo.request && (
|
||||
<p className="text-white/50 text-xs mt-2">요청자: {todo.request}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="text-center text-white/50 py-8">
|
||||
<svg className="w-8 h-8 mx-auto mb-2 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
</svg>
|
||||
급한 할일이 없습니다
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 출근 대상자 모달 */}
|
||||
<TableModal
|
||||
isOpen={modals.presentUsers}
|
||||
onClose={() => hideModal('presentUsers')}
|
||||
title="금일 출근 대상자 목록"
|
||||
headers={['사번', '이름', '공정', '직급', '상태', '이메일']}
|
||||
data={modalData.presentUsers}
|
||||
renderRow={(user, index) => (
|
||||
<tr key={index} className="hover:bg-white/5">
|
||||
<td className="px-6 py-4 text-white text-sm">{user.id || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{user.name || '이름 없음'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{user.gname || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{user.level || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-success-400 text-sm">출근</td>
|
||||
<td className="px-6 py-4 text-white/70 text-sm">{user.email || 'N/A'}</td>
|
||||
</tr>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 휴가 요청 모달 */}
|
||||
<TableModal
|
||||
isOpen={modals.holidayRequest}
|
||||
onClose={() => hideModal('holidayRequest')}
|
||||
title="휴가 신청 목록"
|
||||
maxWidth="max-w-6xl"
|
||||
headers={['사번', '이름', '항목', '일자', '요청일', '요청시간', '비고']}
|
||||
data={modalData.holidayRequests}
|
||||
renderRow={(request, index) => (
|
||||
<tr key={index} className="hover:bg-white/5">
|
||||
<td className="px-6 py-4 text-white text-sm">{request.uid || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{request.name || '이름 없음'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{request.cate || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">
|
||||
{request.sdate && request.edate ? `${request.sdate} ~ ${request.edate}` : 'N/A'}
|
||||
</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{request.holydays || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{request.holytimes || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white/70 text-sm">{request.HolyReason || request.remark || 'N/A'}</td>
|
||||
</tr>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 구매요청 NR 모달 */}
|
||||
<TableModal
|
||||
isOpen={modals.purchaseNR}
|
||||
onClose={() => hideModal('purchaseNR')}
|
||||
title="구매요청(NR) 목록"
|
||||
maxWidth="max-w-7xl"
|
||||
headers={['요청일', '공정', '품목', '규격', '단위', '수량', '단가', '금액']}
|
||||
data={modalData.purchaseNR}
|
||||
renderRow={(item, index) => (
|
||||
<tr key={index} className="hover:bg-white/5">
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pdate || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.process || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumname || '품목 없음'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumscale || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumunit || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumqtyreq || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">
|
||||
{item.pumprice ? `₩${Number(item.pumprice).toLocaleString()}` : 'N/A'}
|
||||
</td>
|
||||
<td className="px-6 py-4 text-danger-400 text-sm font-medium">
|
||||
{item.pumamt ? `₩${Number(item.pumamt).toLocaleString()}` : 'N/A'}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 구매요청 CR 모달 */}
|
||||
<TableModal
|
||||
isOpen={modals.purchaseCR}
|
||||
onClose={() => hideModal('purchaseCR')}
|
||||
title="구매요청(CR) 목록"
|
||||
maxWidth="max-w-7xl"
|
||||
headers={['요청일', '공정', '품목', '규격', '단위', '수량', '단가', '금액']}
|
||||
data={modalData.purchaseCR}
|
||||
renderRow={(item, index) => (
|
||||
<tr key={index} className="hover:bg-white/5">
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pdate || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.process || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumname || '품목 없음'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumscale || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumunit || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">{item.pumqtyreq || 'N/A'}</td>
|
||||
<td className="px-6 py-4 text-white text-sm">
|
||||
{item.pumprice ? `₩${Number(item.pumprice).toLocaleString()}` : 'N/A'}
|
||||
</td>
|
||||
<td className="px-6 py-4 text-purple-400 text-sm font-medium">
|
||||
{item.pumamt ? `₩${Number(item.pumamt).toLocaleString()}` : 'N/A'}
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// 개발중 경고 메시지 컴포넌트
|
||||
function DevWarning({ show = false }) {
|
||||
// show props가 false이거나 없으면 아무것도 렌더링하지 않음
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="dev-warning animate-slide-up">
|
||||
<div className="flex items-center">
|
||||
<svg className="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<p className="title">🚧 개발중인 기능입니다</p>
|
||||
<p className="description">일부 기능이 정상적으로 동작하지 않을 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,988 +0,0 @@
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function JobReport() {
|
||||
// 상태 관리
|
||||
const [jobData, setJobData] = useState([]);
|
||||
const [filteredData, setFilteredData] = useState([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(25);
|
||||
const [sortColumn, setSortColumn] = useState('pdate');
|
||||
const [sortDirection, setSortDirection] = useState('desc');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [editData, setEditData] = useState({});
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
|
||||
// 필터 상태
|
||||
const [filters, setFilters] = useState({
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
status: '',
|
||||
type: '',
|
||||
user: '',
|
||||
project: '',
|
||||
search: ''
|
||||
});
|
||||
|
||||
// 통계 데이터
|
||||
const [statistics, setStatistics] = useState({
|
||||
totalDays: 0,
|
||||
todayHours: 0,
|
||||
todayProgress: 0,
|
||||
totalOT: 0,
|
||||
activeProjects: 0
|
||||
});
|
||||
|
||||
// 컴포넌트 마운트시 초기화
|
||||
useEffect(() => {
|
||||
initializeFilters();
|
||||
loadJobData();
|
||||
loadUserList();
|
||||
}, []);
|
||||
|
||||
// 필터 변경 시 데이터 필터링
|
||||
useEffect(() => {
|
||||
filterData();
|
||||
}, [jobData, filters]);
|
||||
|
||||
// 초기 필터 설정 (오늘부터 -2주)
|
||||
const initializeFilters = () => {
|
||||
const now = new Date();
|
||||
const today = now.toISOString().split('T')[0];
|
||||
const twoWeeksAgo = new Date(now.getTime() - (14 * 24 * 60 * 60 * 1000)).toISOString().split('T')[0];
|
||||
|
||||
setFilters(prev => ({
|
||||
...prev,
|
||||
startDate: twoWeeksAgo,
|
||||
endDate: today
|
||||
}));
|
||||
};
|
||||
|
||||
// 업무일지 데이터 로드
|
||||
const loadJobData = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
let url = '/Jobreport/GetJobData';
|
||||
const params = new URLSearchParams();
|
||||
if (filters.startDate) params.append('startDate', filters.startDate);
|
||||
if (filters.endDate) params.append('endDate', filters.endDate);
|
||||
if (filters.user) params.append('user', filters.user);
|
||||
|
||||
if (params.toString()) {
|
||||
url += '?' + params.toString();
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: 데이터를 불러오는데 실패했습니다.`);
|
||||
}
|
||||
|
||||
const responseText = await response.text();
|
||||
const responseData = JSON.parse(responseText);
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
setJobData(responseData);
|
||||
} else if (responseData.error) {
|
||||
throw new Error(responseData.error);
|
||||
} else {
|
||||
setJobData([]);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading job data:', error);
|
||||
setJobData([]);
|
||||
showNotification('데이터를 불러오는데 실패했습니다: ' + error.message, 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 사용자 목록 로드
|
||||
const loadUserList = async () => {
|
||||
try {
|
||||
const response = await fetch('/Jobreport/GetUsers');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
// 사용자 데이터를 상태로 저장 (필요시)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('사용자 목록 로드 중 오류:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 통계 업데이트
|
||||
useEffect(() => {
|
||||
updateStatistics();
|
||||
}, [jobData]);
|
||||
|
||||
const updateStatistics = () => {
|
||||
const totalDays = new Set(jobData.map(item => item.pdate)).size;
|
||||
const totalOT = jobData.reduce((sum, item) => sum + (parseFloat(item.ot) || 0), 0);
|
||||
const activeProjects = new Set(jobData.filter(item => item.status === '진행중').map(item => item.projectName)).size;
|
||||
|
||||
const now = new Date();
|
||||
const today = now.toISOString().split('T')[0];
|
||||
|
||||
const todayData = jobData.filter(item => {
|
||||
if (!item.pdate) return false;
|
||||
const itemDate = item.pdate.toString();
|
||||
if (itemDate.length >= 10) {
|
||||
return itemDate.substring(0, 10) === today;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
let todayHours = 0;
|
||||
if (todayData.length > 0) {
|
||||
todayHours = todayData.reduce((sum, item) => sum + (parseFloat(item.hrs) || 0), 0);
|
||||
}
|
||||
const todayProgress = (todayHours / 8) * 100;
|
||||
|
||||
setStatistics({
|
||||
totalDays,
|
||||
todayHours,
|
||||
todayProgress,
|
||||
totalOT,
|
||||
activeProjects
|
||||
});
|
||||
};
|
||||
|
||||
// 데이터 필터링
|
||||
const filterData = () => {
|
||||
let filtered = jobData.filter(item => {
|
||||
const statusMatch = !filters.status || item.status === filters.status;
|
||||
const typeMatch = !filters.type || item.type === filters.type;
|
||||
const projectMatch = !filters.project || item.projectName === filters.project;
|
||||
const searchMatch = !filters.search ||
|
||||
(item.description && item.description.toLowerCase().includes(filters.search.toLowerCase())) ||
|
||||
(item.projectName && item.projectName.toLowerCase().includes(filters.search.toLowerCase())) ||
|
||||
(item.requestpart && item.requestpart.toLowerCase().includes(filters.search.toLowerCase()));
|
||||
|
||||
return statusMatch && typeMatch && projectMatch && searchMatch;
|
||||
});
|
||||
|
||||
// 정렬
|
||||
filtered.sort((a, b) => {
|
||||
let aVal = a[sortColumn];
|
||||
let bVal = b[sortColumn];
|
||||
|
||||
if (sortColumn === 'pdate') {
|
||||
aVal = new Date(aVal);
|
||||
bVal = new Date(bVal);
|
||||
} else if (['hrs', 'ot'].includes(sortColumn)) {
|
||||
aVal = parseFloat(aVal) || 0;
|
||||
bVal = parseFloat(bVal) || 0;
|
||||
} else {
|
||||
aVal = (aVal || '').toString().toLowerCase();
|
||||
bVal = (bVal || '').toString().toLowerCase();
|
||||
}
|
||||
|
||||
if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1;
|
||||
if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
setFilteredData(filtered);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
// 필터 변경 핸들러
|
||||
const handleFilterChange = (field, value) => {
|
||||
setFilters(prev => ({ ...prev, [field]: value }));
|
||||
|
||||
// 날짜 필터 변경시 데이터 다시 로드
|
||||
if (field === 'startDate' || field === 'endDate' || field === 'user') {
|
||||
setTimeout(() => loadJobData(), 100);
|
||||
}
|
||||
};
|
||||
|
||||
// 필터 초기화
|
||||
const clearFilters = () => {
|
||||
const now = new Date();
|
||||
const today = now.toISOString().split('T')[0];
|
||||
const twoWeeksAgo = new Date(now.getTime() - (14 * 24 * 60 * 60 * 1000)).toISOString().split('T')[0];
|
||||
|
||||
setFilters({
|
||||
startDate: twoWeeksAgo,
|
||||
endDate: today,
|
||||
status: '',
|
||||
type: '',
|
||||
user: '',
|
||||
project: '',
|
||||
search: ''
|
||||
});
|
||||
|
||||
setTimeout(() => loadJobData(), 100);
|
||||
};
|
||||
|
||||
// 정렬 처리
|
||||
const handleSort = (column) => {
|
||||
if (sortColumn === column) {
|
||||
setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
|
||||
} else {
|
||||
setSortColumn(column);
|
||||
setSortDirection('asc');
|
||||
}
|
||||
};
|
||||
|
||||
// 추가 모달 표시
|
||||
const showAddJobModal = () => {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
setIsEditMode(false);
|
||||
setEditData({
|
||||
idx: '',
|
||||
pdate: today,
|
||||
status: '진행 중',
|
||||
projectName: '',
|
||||
requestpart: '',
|
||||
type: '',
|
||||
hrs: '8',
|
||||
ot: '',
|
||||
otStart: '',
|
||||
otEnd: '',
|
||||
description: ''
|
||||
});
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
// 편집 모달 표시
|
||||
const showEditJobModal = async (item) => {
|
||||
try {
|
||||
// 상세 정보 로드
|
||||
const response = await fetch(`/Jobreport/GetJobDetail?id=${item.idx}`);
|
||||
if (response.ok) {
|
||||
const fullItem = await response.json();
|
||||
item = fullItem.error ? item : fullItem;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to load full details, using truncated data:', error);
|
||||
}
|
||||
|
||||
setIsEditMode(true);
|
||||
setEditData({
|
||||
idx: item.idx || '',
|
||||
pdate: item.pdate || '',
|
||||
status: item.status || '',
|
||||
projectName: item.projectName || '',
|
||||
requestpart: item.requestpart || '',
|
||||
type: item.type || '',
|
||||
hrs: item.hrs || '',
|
||||
ot: item.ot || '',
|
||||
otStart: item.otStart || '',
|
||||
otEnd: item.otEnd || '',
|
||||
description: item.description || ''
|
||||
});
|
||||
setShowEditModal(true);
|
||||
};
|
||||
|
||||
// 저장 처리
|
||||
const handleSave = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const formData = new URLSearchParams();
|
||||
Object.keys(editData).forEach(key => {
|
||||
if (key !== 'idx' || editData.idx) {
|
||||
formData.append(key, editData[key]);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const url = isEditMode ? '/Jobreport/Edit' : '/Jobreport/Add';
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${isEditMode ? '수정' : '추가'}에 실패했습니다.`);
|
||||
}
|
||||
|
||||
setShowEditModal(false);
|
||||
await loadJobData();
|
||||
showNotification(`업무일지가 성공적으로 ${isEditMode ? '수정' : '추가'}되었습니다.`, 'success');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error saving job:', error);
|
||||
showNotification(`업무일지 ${isEditMode ? '수정' : '추가'} 중 오류가 발생했습니다: ` + error.message, 'error');
|
||||
}
|
||||
};
|
||||
|
||||
// 삭제 처리
|
||||
const handleDelete = async () => {
|
||||
if (!editData.idx) {
|
||||
showNotification('삭제할 수 없는 항목입니다.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.confirm('정말로 이 업무일지를 삭제하시겠습니까?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/Jobreport/Delete/${editData.idx}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('삭제에 실패했습니다.');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
setShowEditModal(false);
|
||||
await loadJobData();
|
||||
showNotification('업무일지가 성공적으로 삭제되었습니다.', 'success');
|
||||
} else {
|
||||
throw new Error(result.message || '삭제에 실패했습니다.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error deleting job:', error);
|
||||
showNotification('업무일지 삭제 중 오류가 발생했습니다: ' + error.message, 'error');
|
||||
}
|
||||
};
|
||||
|
||||
// 엑셀 내보내기
|
||||
const exportToExcel = () => {
|
||||
if (filteredData.length === 0) {
|
||||
showNotification('내보낼 데이터가 없습니다.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const periodText = filters.startDate && filters.endDate ? `_${filters.startDate}_${filters.endDate}` : '';
|
||||
const headers = ['날짜', '상태', '프로젝트명', '요청부서', '타입', '업무내용', '근무시간', '초과근무'];
|
||||
const csvContent = [
|
||||
headers.join(','),
|
||||
...filteredData.map(item => [
|
||||
formatDate(item.pdate),
|
||||
item.status || '',
|
||||
item.projectName || '',
|
||||
item.requestpart || '',
|
||||
item.type || '',
|
||||
`"${(item.description || '').replace(/"/g, '""')}"`,
|
||||
item.hrs || '',
|
||||
item.ot || ''
|
||||
].join(','))
|
||||
].join('\n');
|
||||
|
||||
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
const url = URL.createObjectURL(blob);
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', `업무일지${periodText}_${new Date().toISOString().split('T')[0]}.csv`);
|
||||
link.style.visibility = 'hidden';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
|
||||
// 유틸리티 함수들
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return '-';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('ko-KR');
|
||||
};
|
||||
|
||||
const getStatusColor = (status) => {
|
||||
switch (status) {
|
||||
case '진행 중': return 'bg-blue-100 text-blue-800';
|
||||
case '진행 완료': return 'bg-green-100 text-green-800';
|
||||
case '대기': return 'bg-yellow-100 text-yellow-800';
|
||||
default: return 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
};
|
||||
|
||||
// 알림 표시 함수
|
||||
const showNotification = (message, type = 'info') => {
|
||||
const colors = {
|
||||
info: 'bg-blue-500/90 backdrop-blur-sm',
|
||||
success: 'bg-green-500/90 backdrop-blur-sm',
|
||||
warning: 'bg-yellow-500/90 backdrop-blur-sm',
|
||||
error: 'bg-red-500/90 backdrop-blur-sm'
|
||||
};
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`;
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<span class="ml-2">${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(0)';
|
||||
notification.style.opacity = '1';
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// 페이지네이션
|
||||
const maxPage = Math.ceil(filteredData.length / pageSize);
|
||||
const startIndex = (currentPage - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
const pageData = filteredData.slice(startIndex, endIndex);
|
||||
|
||||
// 프로젝트 목록 업데이트
|
||||
const uniqueProjects = [...new Set(jobData.map(item => item.projectName).filter(Boolean))];
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 개발중 경고 메시지 */}
|
||||
<div className="bg-orange-500 rounded-lg p-4 mb-6 border-l-4 border-orange-700 animate-slide-up shadow-lg">
|
||||
<div className="flex items-center">
|
||||
<svg className="w-5 h-5 text-orange-900 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<p className="text-white font-bold text-base">🚧 개발중인 기능입니다</p>
|
||||
<p className="text-orange-100 text-sm font-medium">일부 기능이 정상적으로 동작하지 않을 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 통계 카드 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8 animate-slide-up">
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-primary-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">총 업무일수</p>
|
||||
<p className="text-2xl font-bold text-white">{statistics.totalDays}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-success-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">오늘 근무시간</p>
|
||||
<p className={`text-2xl font-bold ${statistics.todayHours < 8 ? 'text-red-300' : 'text-green-300'}`}>
|
||||
{statistics.todayHours.toFixed(1)}h
|
||||
</p>
|
||||
<p className="text-sm text-white/60">(목표 8시간의 {statistics.todayProgress.toFixed(0)}%)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-warning-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">총 초과근무</p>
|
||||
<p className="text-2xl font-bold text-white">{statistics.totalOT.toFixed(1)}h</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-purple-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">진행중 프로젝트</p>
|
||||
<p className="text-2xl font-bold text-white">{statistics.activeProjects}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 필터 및 검색 */}
|
||||
<div className="glass-effect rounded-lg mb-6 animate-slide-up">
|
||||
<div className="p-4">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
{/* 좌측: 필터 컨트롤 */}
|
||||
<div className="lg:col-span-2 space-y-3">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">조회기간</label>
|
||||
<div className="flex space-x-1">
|
||||
<input
|
||||
type="date"
|
||||
value={filters.startDate}
|
||||
onChange={(e) => handleFilterChange('startDate', e.target.value)}
|
||||
className="flex-1 bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
/>
|
||||
<span className="flex items-center text-white/60 text-xs">~</span>
|
||||
<input
|
||||
type="date"
|
||||
value={filters.endDate}
|
||||
onChange={(e) => handleFilterChange('endDate', e.target.value)}
|
||||
className="flex-1 bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">상태</label>
|
||||
<select
|
||||
value={filters.status}
|
||||
onChange={(e) => handleFilterChange('status', e.target.value)}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
>
|
||||
<option value="">전체</option>
|
||||
<option value="진행중">진행중</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">타입</label>
|
||||
<select
|
||||
value={filters.type}
|
||||
onChange={(e) => handleFilterChange('type', e.target.value)}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
>
|
||||
<option value="">전체</option>
|
||||
<option value="개발">개발</option>
|
||||
<option value="유지보수">유지보수</option>
|
||||
<option value="분석">분석</option>
|
||||
<option value="테스트">테스트</option>
|
||||
<option value="문서작업">문서작업</option>
|
||||
<option value="회의">회의</option>
|
||||
<option value="기타">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">프로젝트</label>
|
||||
<select
|
||||
value={filters.project}
|
||||
onChange={(e) => handleFilterChange('project', e.target.value)}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
>
|
||||
<option value="">전체</option>
|
||||
{uniqueProjects.map(project => (
|
||||
<option key={project} value={project}>{project}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">검색</label>
|
||||
<input
|
||||
type="text"
|
||||
value={filters.search}
|
||||
onChange={(e) => handleFilterChange('search', e.target.value)}
|
||||
placeholder="업무 내용 검색..."
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 액션 버튼들 */}
|
||||
<div className="flex flex-col space-y-2 justify-center">
|
||||
<button
|
||||
onClick={showAddJobModal}
|
||||
className="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-md flex items-center justify-center transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
업무일지 추가
|
||||
</button>
|
||||
<button
|
||||
onClick={exportToExcel}
|
||||
className="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md flex items-center justify-center transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
엑셀 다운로드
|
||||
</button>
|
||||
<button
|
||||
onClick={clearFilters}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-md flex items-center justify-center transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
필터 초기화
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 데이터 테이블 */}
|
||||
<div className="glass-effect rounded-lg overflow-hidden animate-slide-up custom-scrollbar">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full divide-y divide-white/20">
|
||||
<thead className="bg-white/10">
|
||||
<tr>
|
||||
<th
|
||||
className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider cursor-pointer hover:bg-white/20 transition-colors"
|
||||
onClick={() => handleSort('pdate')}
|
||||
>
|
||||
날짜 <svg className="w-4 h-4 inline ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th
|
||||
className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider cursor-pointer hover:bg-white/20 transition-colors"
|
||||
onClick={() => handleSort('status')}
|
||||
>
|
||||
상태 <svg className="w-4 h-4 inline ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th
|
||||
className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider cursor-pointer hover:bg-white/20 transition-colors"
|
||||
onClick={() => handleSort('hrs')}
|
||||
>
|
||||
근무시간 <svg className="w-4 h-4 inline ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th
|
||||
className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider cursor-pointer hover:bg-white/20 transition-colors"
|
||||
onClick={() => handleSort('projectName')}
|
||||
>
|
||||
프로젝트명 <svg className="w-4 h-4 inline ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">업무내용</th>
|
||||
<th
|
||||
className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider cursor-pointer hover:bg-white/20 transition-colors"
|
||||
onClick={() => handleSort('requestpart')}
|
||||
>
|
||||
요청부서 <svg className="w-4 h-4 inline ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</th>
|
||||
<th
|
||||
className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider cursor-pointer hover:bg-white/20 transition-colors"
|
||||
onClick={() => handleSort('type')}
|
||||
>
|
||||
타입 <svg className="w-4 h-4 inline ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{isLoading ? (
|
||||
<tr>
|
||||
<td colSpan="7" className="p-8 text-center">
|
||||
<div className="inline-flex items-center">
|
||||
<svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span className="text-white/80">데이터를 불러오는 중...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : pageData.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="7" className="p-8 text-center">
|
||||
<svg className="w-12 h-12 text-white/60 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"></path>
|
||||
</svg>
|
||||
<p className="text-white/70">업무일지 데이터가 없습니다.</p>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
pageData.map((item, index) => {
|
||||
const hrs = parseFloat(item.hrs) || 0;
|
||||
const ot = parseFloat(item.ot) || 0;
|
||||
let workTimeDisplay = '';
|
||||
|
||||
if (hrs > 0) {
|
||||
workTimeDisplay = hrs.toFixed(1);
|
||||
if (ot > 0) {
|
||||
workTimeDisplay += '+' + ot.toFixed(1);
|
||||
}
|
||||
} else {
|
||||
workTimeDisplay = '-';
|
||||
}
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={item.idx || index}
|
||||
className="hover:bg-white/10 cursor-pointer transition-colors"
|
||||
onClick={() => showEditJobModal(item)}
|
||||
>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{formatDate(item.pdate)}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getStatusColor(item.status)}`}>
|
||||
{item.status || '-'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{workTimeDisplay}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
<div className="flex items-center">
|
||||
<span>{item.projectName || '-'}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-white">
|
||||
<div className="max-w-xs truncate" title={item.description || ''}>
|
||||
{item.description || '-'}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{item.requestpart || '-'}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{item.type || '-'}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 페이지네이션 */}
|
||||
<div className="mt-6 flex items-center justify-between glass-effect rounded-lg p-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-sm text-white/80">페이지당 행 수:</span>
|
||||
<select
|
||||
value={pageSize}
|
||||
onChange={(e) => {
|
||||
setPageSize(parseInt(e.target.value));
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
className="bg-white/20 border border-white/30 rounded-md px-2 py-1 text-sm text-white"
|
||||
>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
|
||||
disabled={currentPage <= 1}
|
||||
className="px-3 py-1 border border-white/30 rounded-md text-sm text-white hover:bg-white/20 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
이전
|
||||
</button>
|
||||
<span className="text-sm text-white/80">{currentPage} / {maxPage}</span>
|
||||
<button
|
||||
onClick={() => setCurrentPage(Math.min(maxPage, currentPage + 1))}
|
||||
disabled={currentPage >= maxPage}
|
||||
className="px-3 py-1 border border-white/30 rounded-md text-sm text-white hover:bg-white/20 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
다음
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 편집 모달 */}
|
||||
{showEditModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-6xl animate-slide-up">
|
||||
{/* 모달 헤더 */}
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||
</svg>
|
||||
업무일지 {isEditMode ? '편집' : '추가'}
|
||||
</h2>
|
||||
<button
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="text-white/70 hover:text-white transition-colors"
|
||||
>
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 모달 내용 */}
|
||||
<form onSubmit={handleSave} className="p-6">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-5 gap-8">
|
||||
{/* 좌측: 기본 정보 */}
|
||||
<div className="lg:col-span-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">날짜 *</label>
|
||||
<input
|
||||
type="date"
|
||||
value={editData.pdate || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, pdate: e.target.value}))}
|
||||
required
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">상태 *</label>
|
||||
<select
|
||||
value={editData.status || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, status: e.target.value}))}
|
||||
required
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
>
|
||||
<option value="">선택하세요</option>
|
||||
<option value="진행 중">진행 중</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
<option value="보류">보류</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">요청부서</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.requestpart || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, requestpart: e.target.value}))}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">타입</label>
|
||||
<select
|
||||
value={editData.type || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, type: e.target.value}))}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
>
|
||||
<option value="">선택하세요</option>
|
||||
<option value="개발">개발</option>
|
||||
<option value="유지보수">유지보수</option>
|
||||
<option value="분석">분석</option>
|
||||
<option value="테스트">테스트</option>
|
||||
<option value="문서작업">문서작업</option>
|
||||
<option value="회의">회의</option>
|
||||
<option value="기타">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">근무시간 (시간) *</label>
|
||||
<input
|
||||
type="number"
|
||||
step="any"
|
||||
value={editData.hrs || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, hrs: e.target.value}))}
|
||||
required
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">초과근무 (시간)</label>
|
||||
<input
|
||||
type="number"
|
||||
step="any"
|
||||
value={editData.ot || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, ot: e.target.value}))}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">초과근무 시작시간</label>
|
||||
<input
|
||||
type="time"
|
||||
value={editData.otStart || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, otStart: e.target.value}))}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">초과근무 종료시간</label>
|
||||
<input
|
||||
type="time"
|
||||
value={editData.otEnd || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, otEnd: e.target.value}))}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 프로젝트명과 업무내용 */}
|
||||
<div className="lg:col-span-3 space-y-4">
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">프로젝트명 *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editData.projectName || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, projectName: e.target.value}))}
|
||||
required
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">업무내용 *</label>
|
||||
<textarea
|
||||
value={editData.description || ''}
|
||||
onChange={(e) => setEditData(prev => ({...prev, description: e.target.value}))}
|
||||
rows="15"
|
||||
required
|
||||
className="w-full h-full min-h-[360px] bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all resize-vertical"
|
||||
placeholder="상세한 업무 내용을 입력하세요..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* 모달 푸터 */}
|
||||
<div className="px-6 py-4 border-t border-white/10 flex justify-between items-center bg-black/10 rounded-b-2xl">
|
||||
{isEditMode && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDelete}
|
||||
className="bg-danger-500 hover:bg-danger-600 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
삭제
|
||||
</button>
|
||||
)}
|
||||
<div className="flex space-x-3 ml-auto">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowEditModal(false)}
|
||||
className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
onClick={handleSave}
|
||||
className="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors"
|
||||
>
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function Kuntae() {
|
||||
// 상태 관리
|
||||
const [kuntaeData, setKuntaeData] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [filters, setFilters] = useState({
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
});
|
||||
|
||||
// 통계 데이터
|
||||
const [statistics, setStatistics] = useState({
|
||||
totalDays: 0,
|
||||
approvedDays: 0,
|
||||
pendingDays: 0,
|
||||
rejectedDays: 0
|
||||
});
|
||||
|
||||
// 컴포넌트 마운트시 초기화
|
||||
useEffect(() => {
|
||||
initializeFilters();
|
||||
}, []);
|
||||
|
||||
// 초기 필터 설정 (이번 달)
|
||||
const initializeFilters = () => {
|
||||
const now = new Date();
|
||||
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
||||
|
||||
setFilters({
|
||||
startDate: firstDay.toISOString().split('T')[0],
|
||||
endDate: lastDay.toISOString().split('T')[0]
|
||||
});
|
||||
|
||||
// 초기 데이터 로드
|
||||
loadKuntaeData({
|
||||
startDate: firstDay.toISOString().split('T')[0],
|
||||
endDate: lastDay.toISOString().split('T')[0]
|
||||
});
|
||||
};
|
||||
|
||||
// 근태 데이터 로드
|
||||
const loadKuntaeData = async (searchFilters = filters) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
let url = '/Kuntae/GetData';
|
||||
const params = new URLSearchParams();
|
||||
if (searchFilters.startDate) params.append('startDate', searchFilters.startDate);
|
||||
if (searchFilters.endDate) params.append('endDate', searchFilters.endDate);
|
||||
|
||||
if (params.toString()) {
|
||||
url += '?' + params.toString();
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: 데이터를 불러오는데 실패했습니다.`);
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
if (Array.isArray(responseData)) {
|
||||
setKuntaeData(responseData);
|
||||
updateStatistics(responseData);
|
||||
} else if (responseData.error) {
|
||||
throw new Error(responseData.error);
|
||||
} else {
|
||||
setKuntaeData([]);
|
||||
updateStatistics([]);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading kuntae data:', error);
|
||||
setKuntaeData([]);
|
||||
updateStatistics([]);
|
||||
showNotification('데이터를 불러오는데 실패했습니다: ' + error.message, 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 통계 업데이트
|
||||
const updateStatistics = (data) => {
|
||||
const totalDays = data.length;
|
||||
const approvedDays = data.filter(item => item.status === '승인').length;
|
||||
const pendingDays = data.filter(item => item.status === '대기').length;
|
||||
const rejectedDays = data.filter(item => item.status === '반려').length;
|
||||
|
||||
setStatistics({
|
||||
totalDays,
|
||||
approvedDays,
|
||||
pendingDays,
|
||||
rejectedDays
|
||||
});
|
||||
};
|
||||
|
||||
// 필터 변경 핸들러
|
||||
const handleFilterChange = (field, value) => {
|
||||
setFilters(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
// 검색 실행
|
||||
const handleSearch = () => {
|
||||
loadKuntaeData();
|
||||
};
|
||||
|
||||
// 유틸리티 함수들
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return '-';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('ko-KR');
|
||||
};
|
||||
|
||||
const getStatusColor = (status) => {
|
||||
switch (status) {
|
||||
case '승인': return 'bg-green-100 text-green-800';
|
||||
case '대기': return 'bg-yellow-100 text-yellow-800';
|
||||
case '반려': return 'bg-red-100 text-red-800';
|
||||
default: return 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
};
|
||||
|
||||
// 알림 표시 함수
|
||||
const showNotification = (message, type = 'info') => {
|
||||
const colors = {
|
||||
info: 'bg-blue-500/90 backdrop-blur-sm',
|
||||
success: 'bg-green-500/90 backdrop-blur-sm',
|
||||
warning: 'bg-yellow-500/90 backdrop-blur-sm',
|
||||
error: 'bg-red-500/90 backdrop-blur-sm'
|
||||
};
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`;
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<span class="ml-2">${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(0)';
|
||||
notification.style.opacity = '1';
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 개발중 경고 메시지 */}
|
||||
<div className="bg-orange-500 rounded-lg p-4 mb-6 border-l-4 border-orange-700 animate-slide-up shadow-lg">
|
||||
<div className="flex items-center">
|
||||
<svg className="w-5 h-5 text-orange-900 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<p className="text-white font-bold text-base">🚧 개발중인 기능입니다</p>
|
||||
<p className="text-orange-100 text-sm font-medium">일부 기능이 정상적으로 동작하지 않을 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 검색 및 필터 섹션 */}
|
||||
<div className="glass-effect rounded-lg p-6 mb-6 animate-slide-up">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">시작일</label>
|
||||
<input
|
||||
type="date"
|
||||
value={filters.startDate}
|
||||
onChange={(e) => handleFilterChange('startDate', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 border border-white/30 rounded-md text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">종료일</label>
|
||||
<input
|
||||
type="date"
|
||||
value={filters.endDate}
|
||||
onChange={(e) => handleFilterChange('endDate', e.target.value)}
|
||||
className="w-full px-3 py-2 bg-white/20 border border-white/30 rounded-md text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<button
|
||||
onClick={handleSearch}
|
||||
disabled={isLoading}
|
||||
className="w-full glass-effect text-white px-4 py-2 rounded-md hover:bg-white/30 transition-colors duration-200 flex items-center justify-center disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<div className="loading inline-block w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin mr-2"></div>
|
||||
로딩중...
|
||||
</>
|
||||
) : (
|
||||
'조회'
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 통계 카드 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6 animate-slide-up">
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-primary-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">총 신청건</p>
|
||||
<p className="text-2xl font-bold text-white">{statistics.totalDays}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-success-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">승인</p>
|
||||
<p className="text-2xl font-bold text-green-300">{statistics.approvedDays}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-warning-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">대기</p>
|
||||
<p className="text-2xl font-bold text-yellow-300">{statistics.pendingDays}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 card-hover">
|
||||
<div className="flex items-center">
|
||||
<div className="p-3 bg-red-500/20 rounded-lg">
|
||||
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="text-sm font-medium text-white/80">반려</p>
|
||||
<p className="text-2xl font-bold text-red-300">{statistics.rejectedDays}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 데이터 테이블 */}
|
||||
<div className="glass-effect rounded-lg overflow-hidden animate-slide-up">
|
||||
<div className="table-container custom-scrollbar" style={{ maxHeight: '600px', overflowY: 'auto' }}>
|
||||
<table className="min-w-full divide-y divide-white/20">
|
||||
<thead className="bg-white/10 sticky top-0">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">신청일</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">시작일</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">종료일</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">휴가종류</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">일수</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">상태</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider">사유</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{isLoading ? (
|
||||
<tr>
|
||||
<td colSpan="7" className="p-8 text-center">
|
||||
<div className="inline-flex items-center">
|
||||
<div className="loading inline-block w-5 h-5 border-3 border-white/30 border-t-white rounded-full animate-spin mr-3"></div>
|
||||
<span className="text-white/80">데이터를 불러오는 중...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : kuntaeData.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="7" className="p-8 text-center">
|
||||
<svg className="w-12 h-12 text-white/60 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<p className="text-white/70">근태 데이터가 없습니다.</p>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
kuntaeData.map((item, index) => (
|
||||
<tr key={item.idx || index} className="hover:bg-white/10 transition-colors">
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{formatDate(item.requestDate)}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{formatDate(item.startDate)}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{formatDate(item.endDate)}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{item.type || '-'}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-white">
|
||||
{item.days || '0'}일
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<span className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getStatusColor(item.status)}`}>
|
||||
{item.status || '-'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-white">
|
||||
<div className="max-w-xs truncate" title={item.reason || ''}>
|
||||
{item.reason || '-'}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
// LoginApp.jsx - React Login Component for GroupWare
|
||||
const { useState, useEffect, useRef } = React;
|
||||
|
||||
function LoginApp() {
|
||||
const [formData, setFormData] = useState({
|
||||
gcode: '',
|
||||
userId: '',
|
||||
password: '',
|
||||
rememberMe: false
|
||||
});
|
||||
|
||||
const [userGroups, setUserGroups] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [message, setMessage] = useState({ type: '', text: '', show: false });
|
||||
const [isFormReady, setIsFormReady] = useState(false);
|
||||
|
||||
const gcodeRef = useRef(null);
|
||||
const userIdRef = useRef(null);
|
||||
const passwordRef = useRef(null);
|
||||
|
||||
// 메시지 표시 함수
|
||||
const showMessage = (type, text) => {
|
||||
setMessage({ type, text, show: true });
|
||||
setTimeout(() => {
|
||||
setMessage(prev => ({ ...prev, show: false }));
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// 폼 데이터 업데이트
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value, type, checked } = e.target;
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: type === 'checkbox' ? checked : value
|
||||
}));
|
||||
};
|
||||
|
||||
// 사용자 그룹 목록 로드
|
||||
const loadUserGroups = async () => {
|
||||
try {
|
||||
const response = await fetch('/DashBoard/GetUserGroups');
|
||||
const data = await response.json();
|
||||
|
||||
// 유효한 그룹만 필터링
|
||||
const validGroups = data.filter(group => group.gcode && group.name);
|
||||
setUserGroups(validGroups);
|
||||
|
||||
// 이전 로그인 정보 로드
|
||||
await loadPreviousLoginInfo();
|
||||
|
||||
} catch (error) {
|
||||
console.error('그룹 목록 로드 중 오류 발생:', error);
|
||||
showMessage('error', '부서 목록을 불러오는 중 오류가 발생했습니다.');
|
||||
}
|
||||
};
|
||||
|
||||
// 이전 로그인 정보 로드
|
||||
const loadPreviousLoginInfo = async () => {
|
||||
try {
|
||||
const response = await fetch('/Home/GetPreviousLoginInfo');
|
||||
const result = await response.json();
|
||||
|
||||
if (result.Success && result.Data) {
|
||||
const { Gcode, UserId } = result.Data;
|
||||
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
gcode: Gcode || '',
|
||||
userId: UserId ? UserId.split(';')[0] : ''
|
||||
}));
|
||||
|
||||
// 포커스 설정
|
||||
setTimeout(() => {
|
||||
if (Gcode && UserId) {
|
||||
passwordRef.current?.focus();
|
||||
} else {
|
||||
gcodeRef.current?.focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
setIsFormReady(true);
|
||||
|
||||
} catch (error) {
|
||||
console.error('이전 로그인 정보 로드 중 오류 발생:', error);
|
||||
setIsFormReady(true);
|
||||
setTimeout(() => {
|
||||
gcodeRef.current?.focus();
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// 로그인 처리
|
||||
const handleLogin = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const { gcode, userId, password, rememberMe } = formData;
|
||||
|
||||
// 유효성 검사
|
||||
if (!gcode || !userId || !password) {
|
||||
showMessage('error', '그룹코드/사용자ID/비밀번호를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch('/Home/Login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
Gcode: gcode,
|
||||
UserId: userId,
|
||||
Password: password,
|
||||
RememberMe: rememberMe
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
// 로그인 성공
|
||||
showMessage('success', data.Message);
|
||||
|
||||
// WebView2에 로그인 성공 메시지 전송
|
||||
if (window.chrome && window.chrome.webview) {
|
||||
window.chrome.webview.postMessage('LOGIN_SUCCESS');
|
||||
}
|
||||
|
||||
// 리다이렉트 URL이 있으면 이동
|
||||
if (data.RedirectUrl) {
|
||||
setTimeout(() => {
|
||||
window.location.href = data.RedirectUrl;
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
// 로그인 실패
|
||||
showMessage('error', data.Message || '로그인에 실패했습니다.');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('로그인 요청 중 오류 발생:', error);
|
||||
showMessage('error', '서버 연결에 실패했습니다. 다시 시도해주세요.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 컴포넌트 마운트 시 실행
|
||||
useEffect(() => {
|
||||
loadUserGroups();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="gradient-bg min-h-screen flex items-center justify-center p-4">
|
||||
<div className="w-full max-w-md">
|
||||
{/* 로그인 카드 */}
|
||||
<div className="glass-effect rounded-3xl p-8 card-hover animate-bounce-in">
|
||||
{/* 로고 및 제목 */}
|
||||
<div className="text-center mb-8 animate-fade-in">
|
||||
<div className="w-16 h-16 bg-white/20 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white mb-2">GroupWare</h1>
|
||||
<p className="text-white/70 text-sm">로그인하여 시스템에 접속하세요</p>
|
||||
</div>
|
||||
|
||||
{/* 로그인 폼 */}
|
||||
<form onSubmit={handleLogin} className="space-y-6 animate-slide-up">
|
||||
{/* Gcode 드롭다운 */}
|
||||
<div className="relative">
|
||||
<select
|
||||
ref={gcodeRef}
|
||||
name="gcode"
|
||||
value={formData.gcode}
|
||||
onChange={handleInputChange}
|
||||
className="input-field w-full px-4 py-3 bg-white/10 border border-white/20 rounded-xl text-white focus:outline-none focus:border-primary-400 input-focus appearance-none"
|
||||
required
|
||||
disabled={!isFormReady}
|
||||
>
|
||||
<option value="" className="text-gray-800">부서를 선택하세요</option>
|
||||
{userGroups.map(group => (
|
||||
<option key={group.gcode} value={group.gcode} className="text-gray-800">
|
||||
{group.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="absolute right-3 top-3 pointer-events-none">
|
||||
<svg className="w-5 h-5 text-white/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 사용자 ID 입력 */}
|
||||
<div className="relative">
|
||||
<input
|
||||
ref={userIdRef}
|
||||
type="text"
|
||||
name="userId"
|
||||
value={formData.userId}
|
||||
onChange={handleInputChange}
|
||||
className="input-field w-full px-4 py-3 bg-white/10 border border-white/20 rounded-xl text-white placeholder-white/60 focus:outline-none focus:border-primary-400 input-focus"
|
||||
placeholder="사원번호"
|
||||
required
|
||||
disabled={!isFormReady}
|
||||
/>
|
||||
<div className="absolute right-3 top-3">
|
||||
<svg className="w-5 h-5 text-white/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 비밀번호 입력 */}
|
||||
<div className="relative">
|
||||
<input
|
||||
ref={passwordRef}
|
||||
type="password"
|
||||
name="password"
|
||||
value={formData.password}
|
||||
onChange={handleInputChange}
|
||||
className="input-field w-full px-4 py-3 bg-white/10 border border-white/20 rounded-xl text-white placeholder-white/60 focus:outline-none focus:border-primary-400 input-focus"
|
||||
placeholder="비밀번호"
|
||||
required
|
||||
disabled={!isFormReady}
|
||||
/>
|
||||
<div className="absolute right-3 top-3">
|
||||
<svg className="w-5 h-5 text-white/40" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 로그인 버튼 */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading || !isFormReady}
|
||||
className="w-full bg-primary-500 hover:bg-primary-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-semibold py-3 px-4 rounded-xl transition-all duration-300 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2 focus:ring-offset-transparent"
|
||||
>
|
||||
<span className="flex items-center justify-center">
|
||||
{isLoading ? (
|
||||
<>
|
||||
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white mr-2"></div>
|
||||
로그인 중...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"></path>
|
||||
</svg>
|
||||
로그인
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{/* 추가 옵션 */}
|
||||
<div className="mt-6 text-center">
|
||||
<div className="flex items-center justify-center space-x-4 text-sm">
|
||||
<label className="flex items-center text-white/70 hover:text-white cursor-pointer transition-colors">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="rememberMe"
|
||||
checked={formData.rememberMe}
|
||||
onChange={handleInputChange}
|
||||
className="mr-2 w-4 h-4 text-primary-500 bg-white/10 border-white/20 rounded focus:ring-primary-400 focus:ring-2"
|
||||
/>
|
||||
로그인 정보 저장
|
||||
</label>
|
||||
<a href="#" className="text-primary-300 hover:text-primary-200 transition-colors">비밀번호 찾기</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 푸터 */}
|
||||
<div className="text-center mt-6 animate-fade-in">
|
||||
<p className="text-white/50 text-sm">
|
||||
© 2024 GroupWare System. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 메시지 표시 */}
|
||||
{message.show && (
|
||||
<div className={`fixed top-4 left-1/2 transform -translate-x-1/2 px-6 py-3 rounded-lg shadow-lg animate-slide-up ${
|
||||
message.type === 'error' ? 'bg-red-500' : 'bg-green-500'
|
||||
} text-white`}>
|
||||
<div className="flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
{message.type === 'error' ? (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
) : (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 13l4 4L19 7"></path>
|
||||
)}
|
||||
</svg>
|
||||
<span>{message.text}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,884 +0,0 @@
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function Project() {
|
||||
// 상태 관리
|
||||
const [projects, setProjects] = useState([]);
|
||||
const [filteredProjects, setFilteredProjects] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [currentUser, setCurrentUser] = useState('사용자');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [itemsPerPage] = useState(10);
|
||||
|
||||
// 모달 상태
|
||||
const [showProjectModal, setShowProjectModal] = useState(false);
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [currentProjectIdx, setCurrentProjectIdx] = useState(null);
|
||||
|
||||
// 필터 상태
|
||||
const [filters, setFilters] = useState({
|
||||
status: '진행',
|
||||
search: '',
|
||||
manager: 'my'
|
||||
});
|
||||
|
||||
// UI 상태
|
||||
const [showFilters, setShowFilters] = useState(false);
|
||||
const [showColumnDropdown, setShowColumnDropdown] = useState(false);
|
||||
const [visibleColumns, setVisibleColumns] = useState({
|
||||
serial: false,
|
||||
plant: false,
|
||||
line: false,
|
||||
package: false,
|
||||
staff: false,
|
||||
process: false,
|
||||
expire: false,
|
||||
delivery: false,
|
||||
design: false,
|
||||
electric: false,
|
||||
program: false,
|
||||
budgetDue: false,
|
||||
budget: false,
|
||||
jasmin: false
|
||||
});
|
||||
|
||||
// 프로젝트 폼 상태
|
||||
const [projectForm, setProjectForm] = useState({
|
||||
idx: 0,
|
||||
name: '',
|
||||
process: '',
|
||||
sdate: '',
|
||||
edate: '',
|
||||
ddate: '',
|
||||
odate: '',
|
||||
userManager: '',
|
||||
status: '진행',
|
||||
memo: ''
|
||||
});
|
||||
|
||||
// 통계 상태
|
||||
const [statusCounts, setStatusCounts] = useState({
|
||||
진행: 0,
|
||||
완료: 0,
|
||||
대기: 0,
|
||||
중단: 0
|
||||
});
|
||||
|
||||
// 컴포넌트 마운트시 초기화
|
||||
useEffect(() => {
|
||||
getCurrentUser();
|
||||
loadProjects();
|
||||
}, []);
|
||||
|
||||
// 필터 변경시 프로젝트 목록 새로 로드
|
||||
useEffect(() => {
|
||||
loadProjects();
|
||||
}, [filters.status, filters.manager]);
|
||||
|
||||
// 검색어 변경시 필터링
|
||||
useEffect(() => {
|
||||
filterData();
|
||||
}, [filters.search, projects]);
|
||||
|
||||
// 현재 사용자 정보 가져오기
|
||||
const getCurrentUser = async () => {
|
||||
try {
|
||||
const response = await fetch('/Common/GetCurrentUser');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success && data.Data) {
|
||||
const userName = data.Data.userName || data.Data.name || '사용자';
|
||||
setCurrentUser(userName);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error getting current user:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 프로젝트 목록 로드
|
||||
const loadProjects = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/Project/GetProjects?status=${filters.status}&userFilter=${filters.manager}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
const projectData = data.Data || [];
|
||||
setProjects(projectData);
|
||||
setFilteredProjects(projectData);
|
||||
updateStatusCounts(projectData);
|
||||
|
||||
if (data.CurrentUser) {
|
||||
setCurrentUser(data.CurrentUser);
|
||||
}
|
||||
} else {
|
||||
console.error('Error:', data.Message);
|
||||
showNotification('데이터를 불러오는데 실패했습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showNotification('데이터를 불러오는데 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 상태별 카운트 업데이트
|
||||
const updateStatusCounts = (projectData) => {
|
||||
const counts = { 진행: 0, 완료: 0, 대기: 0, 중단: 0 };
|
||||
|
||||
projectData.forEach(project => {
|
||||
const status = project.상태 || '진행';
|
||||
counts[status] = (counts[status] || 0) + 1;
|
||||
});
|
||||
|
||||
setStatusCounts(counts);
|
||||
};
|
||||
|
||||
// 데이터 필터링
|
||||
const filterData = () => {
|
||||
if (!filters.search.trim()) {
|
||||
setFilteredProjects(projects);
|
||||
setCurrentPage(1);
|
||||
return;
|
||||
}
|
||||
|
||||
const searchTerm = filters.search.toLowerCase();
|
||||
const filtered = projects.filter(project => {
|
||||
return (project.프로젝트명 && project.프로젝트명.toLowerCase().includes(searchTerm)) ||
|
||||
(project.프로젝트공정 && project.프로젝트공정.toLowerCase().includes(searchTerm)) ||
|
||||
(project.자산번호 && project.자산번호.toLowerCase().includes(searchTerm)) ||
|
||||
(project.장비모델 && project.장비모델.toLowerCase().includes(searchTerm)) ||
|
||||
(project.시리얼번호 && project.시리얼번호.toLowerCase().includes(searchTerm)) ||
|
||||
(project.프로젝트관리자 && project.프로젝트관리자.toLowerCase().includes(searchTerm)) ||
|
||||
(project.설계담당 && project.설계담당.toLowerCase().includes(searchTerm)) ||
|
||||
(project.전장담당 && project.전장담당.toLowerCase().includes(searchTerm)) ||
|
||||
(project.프로그램담당 && project.프로그램담당.toLowerCase().includes(searchTerm));
|
||||
});
|
||||
|
||||
setFilteredProjects(filtered);
|
||||
setCurrentPage(1);
|
||||
};
|
||||
|
||||
// 프로젝트 추가 모달 표시
|
||||
const showAddProjectModal = () => {
|
||||
setCurrentProjectIdx(null);
|
||||
setProjectForm({
|
||||
idx: 0,
|
||||
name: '',
|
||||
process: '',
|
||||
sdate: '',
|
||||
edate: '',
|
||||
ddate: '',
|
||||
odate: '',
|
||||
userManager: '',
|
||||
status: '진행',
|
||||
memo: ''
|
||||
});
|
||||
setShowProjectModal(true);
|
||||
};
|
||||
|
||||
// 프로젝트 편집
|
||||
const editProject = async (idx) => {
|
||||
setCurrentProjectIdx(idx);
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch(`/Project/GetProject?id=${idx}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success && data.Data) {
|
||||
const project = data.Data;
|
||||
setProjectForm({
|
||||
idx: project.idx,
|
||||
name: project.프로젝트명 || '',
|
||||
process: project.프로젝트공정 || '',
|
||||
sdate: project.시작일 || '',
|
||||
edate: project.완료일 || '',
|
||||
ddate: project.만료일 || '',
|
||||
odate: project.출고일 || '',
|
||||
userManager: project.프로젝트관리자 || '',
|
||||
status: project.상태 || '진행',
|
||||
memo: project.memo || ''
|
||||
});
|
||||
setShowProjectModal(true);
|
||||
} else {
|
||||
showNotification('프로젝트 정보를 불러오는데 실패했습니다: ' + data.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showNotification('프로젝트 정보를 불러오는데 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 프로젝트 저장 (추가/수정)
|
||||
const saveProject = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
|
||||
const projectData = {
|
||||
...projectForm,
|
||||
idx: currentProjectIdx ? parseInt(projectForm.idx) : 0,
|
||||
sdate: projectForm.sdate || null,
|
||||
edate: projectForm.edate || null,
|
||||
ddate: projectForm.ddate || null,
|
||||
odate: projectForm.odate || null
|
||||
};
|
||||
|
||||
const url = currentProjectIdx ? '/Project/UpdateProject' : '/Project/CreateProject';
|
||||
const method = currentProjectIdx ? 'PUT' : 'POST';
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(projectData)
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
showNotification(data.Message || (currentProjectIdx ? '프로젝트가 수정되었습니다.' : '프로젝트가 추가되었습니다.'), 'success');
|
||||
setShowProjectModal(false);
|
||||
loadProjects();
|
||||
} else {
|
||||
showNotification('오류: ' + data.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showNotification('저장 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 프로젝트 삭제
|
||||
const deleteProject = async () => {
|
||||
if (!currentProjectIdx) return;
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/Project/DeleteProject?id=${currentProjectIdx}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
showNotification(data.Message || '프로젝트가 삭제되었습니다.', 'success');
|
||||
setShowDeleteModal(false);
|
||||
setShowProjectModal(false);
|
||||
loadProjects();
|
||||
} else {
|
||||
showNotification('오류: ' + data.Message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showNotification('삭제 중 오류가 발생했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 필터 초기화
|
||||
const clearFilters = () => {
|
||||
setFilters({
|
||||
status: '진행',
|
||||
search: '',
|
||||
manager: 'my'
|
||||
});
|
||||
};
|
||||
|
||||
// 엑셀 다운로드
|
||||
const exportToExcel = () => {
|
||||
if (filteredProjects.length === 0) {
|
||||
showNotification('내보낼 데이터가 없습니다.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = ['상태', '자산번호', '장비모델', '시리얼번호', '우선순위', '요청국가', '요청공장', '요청라인', '요청부서패키지', '요청자', '프로젝트공정', '시작일', '완료일', '만료일', '출고일', '프로젝트명', '프로젝트관리자', '설계담당', '전장담당', '프로그램담당', '예산만기일', '예산', '웹관리번호'];
|
||||
const csvContent = [
|
||||
headers.join(','),
|
||||
...filteredProjects.map(project => [
|
||||
project.상태 || '',
|
||||
project.자산번호 || '',
|
||||
project.장비모델 || '',
|
||||
project.시리얼번호 || '',
|
||||
project.우선순위 || '',
|
||||
project.요청국가 || '',
|
||||
project.요청공장 || '',
|
||||
project.요청라인 || '',
|
||||
project.요청부서패키지 || '',
|
||||
project.요청자 || '',
|
||||
project.프로젝트공정 || '',
|
||||
project.시작일 || '',
|
||||
project.완료일 || '',
|
||||
project.만료일 || '',
|
||||
project.출고일 || '',
|
||||
project.프로젝트명 || '',
|
||||
project.프로젝트관리자 || '',
|
||||
project.설계담당 || '',
|
||||
project.전장담당 || '',
|
||||
project.프로그램담당 || '',
|
||||
project.예산만기일 || '',
|
||||
project.예산 || '',
|
||||
project.웹관리번호 || ''
|
||||
].join(','))
|
||||
].join('\n');
|
||||
|
||||
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
const url = URL.createObjectURL(blob);
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', `프로젝트목록_${new Date().toISOString().split('T')[0]}.csv`);
|
||||
link.style.visibility = 'hidden';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
|
||||
// 유틸리티 함수들
|
||||
const getStatusClass = (status) => {
|
||||
switch(status) {
|
||||
case '진행': return 'bg-blue-500/20 text-blue-300';
|
||||
case '완료': return 'bg-green-500/20 text-green-300';
|
||||
case '대기': return 'bg-yellow-500/20 text-yellow-300';
|
||||
case '중단': return 'bg-red-500/20 text-red-300';
|
||||
default: return 'bg-gray-500/20 text-gray-300';
|
||||
}
|
||||
};
|
||||
|
||||
const formatDateToMonthDay = (dateString) => {
|
||||
if (!dateString) return '';
|
||||
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
if (isNaN(date.getTime())) return dateString;
|
||||
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${month}-${day}`;
|
||||
} catch (error) {
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
|
||||
// 알림 표시 함수
|
||||
const showNotification = (message, type = 'info') => {
|
||||
const colors = {
|
||||
info: 'bg-blue-500/90 backdrop-blur-sm',
|
||||
success: 'bg-green-500/90 backdrop-blur-sm',
|
||||
warning: 'bg-yellow-500/90 backdrop-blur-sm',
|
||||
error: 'bg-red-500/90 backdrop-blur-sm'
|
||||
};
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`;
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<span class="ml-2">${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(0)';
|
||||
notification.style.opacity = '1';
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// 페이지네이션 계산
|
||||
const totalPages = Math.ceil(filteredProjects.length / itemsPerPage);
|
||||
const startIndex = (currentPage - 1) * itemsPerPage;
|
||||
const endIndex = startIndex + itemsPerPage;
|
||||
const paginatedProjects = filteredProjects.slice(startIndex, endIndex);
|
||||
|
||||
const changePage = (page) => {
|
||||
if (page >= 1 && page <= totalPages) {
|
||||
setCurrentPage(page);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 프로젝트 목록 */}
|
||||
<div className="glass-effect rounded-lg overflow-hidden animate-slide-up">
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
||||
</svg>
|
||||
프로젝트 목록
|
||||
</h2>
|
||||
<div className="flex space-x-3">
|
||||
<button onClick={showAddProjectModal} className="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg transition-colors flex items-center text-sm" title="프로젝트 추가">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
프로젝트 추가
|
||||
</button>
|
||||
<button onClick={() => setShowFilters(!showFilters)} className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors flex items-center text-sm" title="필터 표시/숨김">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707L13 14v6a1 1 0 01-.707.293l-4-1A1 1 0 018 19v-5L0.293 7.293A1 1 0 010 6.586V4z"></path>
|
||||
</svg>
|
||||
필터
|
||||
<svg className={`w-4 h-4 ml-2 transition-transform ${showFilters ? 'rotate-180' : ''}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 상태별 카드 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 p-4 border-b border-white/10">
|
||||
<div className="bg-white/10 rounded-lg p-4 text-center">
|
||||
<div className="text-2xl font-bold text-blue-300 mb-1">{statusCounts.진행}</div>
|
||||
<div className="text-sm text-white/60">진행</div>
|
||||
</div>
|
||||
<div className="bg-white/10 rounded-lg p-4 text-center">
|
||||
<div className="text-2xl font-bold text-green-300 mb-1">{statusCounts.완료}</div>
|
||||
<div className="text-sm text-white/60">완료</div>
|
||||
</div>
|
||||
<div className="bg-white/10 rounded-lg p-4 text-center">
|
||||
<div className="text-2xl font-bold text-yellow-300 mb-1">{statusCounts.대기}</div>
|
||||
<div className="text-sm text-white/60">대기</div>
|
||||
</div>
|
||||
<div className="bg-white/10 rounded-lg p-4 text-center">
|
||||
<div className="text-2xl font-bold text-red-300 mb-1">{statusCounts.중단}</div>
|
||||
<div className="text-sm text-white/60">중단</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 필터 영역 */}
|
||||
{showFilters && (
|
||||
<div className="p-4 border-b border-white/10 animate-slide-up">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
{/* 좌측: 필터 컨트롤 */}
|
||||
<div className="lg:col-span-2 space-y-3">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">상태</label>
|
||||
<select
|
||||
value={filters.status}
|
||||
onChange={(e) => setFilters({...filters, status: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
>
|
||||
<option value="진행">진행</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
<option value="중단">중단</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">검색</label>
|
||||
<input
|
||||
type="text"
|
||||
value={filters.search}
|
||||
onChange={(e) => setFilters({...filters, search: e.target.value})}
|
||||
placeholder="프로젝트명 검색..."
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/80 mb-1">담당자</label>
|
||||
<select
|
||||
value={filters.manager}
|
||||
onChange={(e) => setFilters({...filters, manager: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs"
|
||||
>
|
||||
<option value="my">내 프로젝트</option>
|
||||
<option value="all">전체 프로젝트</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 우측: 액션 버튼들 */}
|
||||
<div className="flex flex-wrap gap-2 justify-end">
|
||||
<div className="relative">
|
||||
<button onClick={() => setShowColumnDropdown(!showColumnDropdown)} className="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg flex items-center transition-colors text-sm" title="컬럼 표시/숨김">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2H9z"></path>
|
||||
</svg>
|
||||
컬럼 설정
|
||||
</button>
|
||||
{showColumnDropdown && (
|
||||
<div className="absolute top-full right-0 bg-gray-800/95 backdrop-blur-sm border border-white/20 rounded-lg p-3 min-w-48 z-50 mt-1">
|
||||
<div className="text-sm font-medium text-white/80 mb-2">표시할 컬럼 선택</div>
|
||||
<div className="space-y-1 text-sm max-h-40 overflow-y-auto">
|
||||
{Object.entries({
|
||||
serial: '시리얼번호',
|
||||
plant: '요청공장',
|
||||
line: '요청라인',
|
||||
package: '요청부서패키지',
|
||||
staff: '요청자',
|
||||
process: '프로젝트공정',
|
||||
expire: '만료일',
|
||||
delivery: '출고일',
|
||||
design: '설계담당',
|
||||
electric: '전장담당',
|
||||
program: '프로그램담당',
|
||||
budgetDue: '예산만기일',
|
||||
budget: '예산',
|
||||
jasmin: '웹관리번호'
|
||||
}).map(([key, label]) => (
|
||||
<label key={key} className="flex items-center text-white cursor-pointer hover:text-blue-300">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={visibleColumns[key]}
|
||||
onChange={(e) => setVisibleColumns({...visibleColumns, [key]: e.target.checked})}
|
||||
className="mr-2"
|
||||
/>
|
||||
{label}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<button onClick={exportToExcel} className="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg flex items-center transition-colors text-sm" title="엑셀 다운로드">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
엑셀 다운로드
|
||||
</button>
|
||||
<button onClick={clearFilters} className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg flex items-center transition-colors text-sm" title="필터 초기화">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
필터 초기화
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 데이터 테이블 */}
|
||||
<div className="px-4 py-3 bg-white/5">
|
||||
<div className="text-sm text-white/70 font-medium">프로젝트 현황</div>
|
||||
</div>
|
||||
<div className="overflow-x-auto custom-scrollbar">
|
||||
<table className="w-full divide-y divide-white/20">
|
||||
<thead className="bg-white/10">
|
||||
<tr>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-20">상태</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 min-w-32">프로젝트명</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">자산번호</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-28">장비모델</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">우선순위</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-20">요청국가</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-28">프로젝트관리자</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">시작일</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">완료일</th>
|
||||
{visibleColumns.serial && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">시리얼번호</th>}
|
||||
{visibleColumns.plant && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-20">요청공장</th>}
|
||||
{visibleColumns.line && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-20">요청라인</th>}
|
||||
{visibleColumns.package && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-28">요청부서패키지</th>}
|
||||
{visibleColumns.staff && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-20">요청자</th>}
|
||||
{visibleColumns.process && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">프로젝트공정</th>}
|
||||
{visibleColumns.expire && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">만료일</th>}
|
||||
{visibleColumns.delivery && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">출고일</th>}
|
||||
{visibleColumns.design && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">설계담당</th>}
|
||||
{visibleColumns.electric && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">전장담당</th>}
|
||||
{visibleColumns.program && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">프로그램담당</th>}
|
||||
{visibleColumns.budgetDue && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-24">예산만기일</th>}
|
||||
{visibleColumns.budget && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider border-r border-white/20 w-20">예산</th>}
|
||||
{visibleColumns.jasmin && <th className="px-3 py-3 text-left text-xs font-medium text-white/80 uppercase tracking-wider w-24">웹관리번호</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{isLoading ? (
|
||||
<tr>
|
||||
<td colSpan="23" className="px-6 py-4 text-center">
|
||||
<div className="inline-flex items-center">
|
||||
<div className="loading inline-block w-5 h-5 border-3 border-white/30 border-t-white rounded-full animate-spin mr-3"></div>
|
||||
<span className="text-white/80">데이터를 불러오는 중...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : paginatedProjects.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="23" className="px-6 py-4 text-center text-white/60">데이터가 없습니다.</td>
|
||||
</tr>
|
||||
) : (
|
||||
paginatedProjects.map(project => (
|
||||
<tr key={project.idx} onClick={() => editProject(project.idx)} className="hover:bg-white/10 cursor-pointer transition-colors">
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusClass(project.상태)}`}>
|
||||
{project.상태 || '진행'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20 font-medium">{project.프로젝트명 || ''}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{project.자산번호 || ''}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{project.장비모델 || ''}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{project.우선순위 || ''}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{project.요청국가 || ''}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{project.프로젝트관리자 || ''}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{formatDateToMonthDay(project.시작일)}</td>
|
||||
<td className="px-4 py-4 text-sm border-r border-white/20">{formatDateToMonthDay(project.완료일)}</td>
|
||||
{visibleColumns.serial && <td className="px-3 py-4 text-sm border-r border-white/20">{project.시리얼번호 || ''}</td>}
|
||||
{visibleColumns.plant && <td className="px-3 py-4 text-sm border-r border-white/20">{project.요청공장 || ''}</td>}
|
||||
{visibleColumns.line && <td className="px-3 py-4 text-sm border-r border-white/20">{project.요청라인 || ''}</td>}
|
||||
{visibleColumns.package && <td className="px-3 py-4 text-sm border-r border-white/20">{project.요청부서패키지 || ''}</td>}
|
||||
{visibleColumns.staff && <td className="px-3 py-4 text-sm border-r border-white/20">{project.요청자 || ''}</td>}
|
||||
{visibleColumns.process && <td className="px-3 py-4 text-sm border-r border-white/20">{project.프로젝트공정 || ''}</td>}
|
||||
{visibleColumns.expire && <td className="px-3 py-4 text-sm border-r border-white/20">{formatDateToMonthDay(project.만료일)}</td>}
|
||||
{visibleColumns.delivery && <td className="px-3 py-4 text-sm border-r border-white/20">{formatDateToMonthDay(project.출고일)}</td>}
|
||||
{visibleColumns.design && <td className="px-3 py-4 text-sm border-r border-white/20">{project.설계담당 || ''}</td>}
|
||||
{visibleColumns.electric && <td className="px-3 py-4 text-sm border-r border-white/20">{project.전장담당 || ''}</td>}
|
||||
{visibleColumns.program && <td className="px-3 py-4 text-sm border-r border-white/20">{project.프로그램담당 || ''}</td>}
|
||||
{visibleColumns.budgetDue && <td className="px-3 py-4 text-sm border-r border-white/20">{formatDateToMonthDay(project.예산만기일)}</td>}
|
||||
{visibleColumns.budget && <td className="px-3 py-4 text-sm border-r border-white/20">{project.예산 || ''}</td>}
|
||||
{visibleColumns.jasmin && (
|
||||
<td className="px-3 py-4 text-sm">
|
||||
{project.웹관리번호 ? (
|
||||
<a href={`https://scwa.amkor.co.kr/jasmine/view/${project.웹관리번호}`} target="_blank" rel="noopener noreferrer" className="text-blue-300 hover:text-blue-200 underline">
|
||||
{project.웹관리번호}
|
||||
</a>
|
||||
) : ''}
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* 페이징 */}
|
||||
<div className="px-4 py-4 border-t border-white/10">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm text-white/60">
|
||||
총 {filteredProjects.length}개 중 {startIndex + 1}-{Math.min(endIndex, filteredProjects.length)}개 표시
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<button onClick={() => changePage(currentPage - 1)} disabled={currentPage <= 1} className="px-3 py-1 bg-white/20 hover:bg-white/30 text-white rounded-md text-sm disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div className="flex space-x-1">
|
||||
{Array.from({length: Math.min(5, totalPages)}, (_, i) => {
|
||||
const pageNum = Math.max(1, currentPage - 2) + i;
|
||||
if (pageNum > totalPages) return null;
|
||||
return (
|
||||
<button
|
||||
key={pageNum}
|
||||
onClick={() => changePage(pageNum)}
|
||||
className={`px-3 py-1 rounded-md text-sm transition-colors ${
|
||||
pageNum === currentPage
|
||||
? 'bg-primary-500 text-white'
|
||||
: 'bg-white/20 hover:bg-white/30 text-white'
|
||||
}`}
|
||||
>
|
||||
{pageNum}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<button onClick={() => changePage(currentPage + 1)} disabled={currentPage >= totalPages} className="px-3 py-1 bg-white/20 hover:bg-white/30 text-white rounded-md text-sm disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 프로젝트 추가/편집 모달 */}
|
||||
{showProjectModal && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-lg w-full max-w-2xl animate-slide-up">
|
||||
<div className="p-6">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h3 className="text-xl font-semibold">{currentProjectIdx ? '프로젝트 편집' : '프로젝트 추가'}</h3>
|
||||
<button onClick={() => setShowProjectModal(false)} className="text-white/60 hover:text-white">
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={saveProject}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">프로젝트명 *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={projectForm.name}
|
||||
onChange={(e) => setProjectForm({...projectForm, name: e.target.value})}
|
||||
required
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">부서</label>
|
||||
<input
|
||||
type="text"
|
||||
value={projectForm.process}
|
||||
onChange={(e) => setProjectForm({...projectForm, process: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">시작일</label>
|
||||
<input
|
||||
type="date"
|
||||
value={projectForm.sdate}
|
||||
onChange={(e) => setProjectForm({...projectForm, sdate: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">종료일</label>
|
||||
<input
|
||||
type="date"
|
||||
value={projectForm.edate}
|
||||
onChange={(e) => setProjectForm({...projectForm, edate: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">개발완료일</label>
|
||||
<input
|
||||
type="date"
|
||||
value={projectForm.ddate}
|
||||
onChange={(e) => setProjectForm({...projectForm, ddate: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">운영개시일</label>
|
||||
<input
|
||||
type="date"
|
||||
value={projectForm.odate}
|
||||
onChange={(e) => setProjectForm({...projectForm, odate: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">담당자</label>
|
||||
<input
|
||||
type="text"
|
||||
value={projectForm.userManager}
|
||||
onChange={(e) => setProjectForm({...projectForm, userManager: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">상태</label>
|
||||
<select
|
||||
value={projectForm.status}
|
||||
onChange={(e) => setProjectForm({...projectForm, status: e.target.value})}
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
>
|
||||
<option value="진행">진행</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
<option value="중단">중단</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-white/80 mb-2">메모</label>
|
||||
<textarea
|
||||
value={projectForm.memo}
|
||||
onChange={(e) => setProjectForm({...projectForm, memo: e.target.value})}
|
||||
rows="3"
|
||||
className="w-full bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center">
|
||||
{currentProjectIdx && (
|
||||
<button type="button" onClick={() => setShowDeleteModal(true)} className="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-md transition-colors">
|
||||
삭제
|
||||
</button>
|
||||
)}
|
||||
<div className="flex space-x-2 ml-auto">
|
||||
<button type="button" onClick={() => setShowProjectModal(false)} className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-md transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button type="submit" className="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-md transition-colors">
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 삭제 확인 모달 */}
|
||||
{showDeleteModal && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-lg w-full max-w-md animate-slide-up">
|
||||
<div className="p-6">
|
||||
<div className="flex items-center mb-4">
|
||||
<svg className="w-8 h-8 text-red-400 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
||||
</svg>
|
||||
<h3 className="text-lg font-semibold">삭제 확인</h3>
|
||||
</div>
|
||||
<p className="text-white/80 mb-6">선택한 프로젝트를 삭제하시겠습니까?<br><span className="text-sm text-gray-500">이 작업은 되돌릴 수 없습니다.</span></p>
|
||||
<div className="flex justify-end space-x-2">
|
||||
<button onClick={() => setShowDeleteModal(false)} className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-md transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button onClick={deleteProject} className="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-md transition-colors">
|
||||
삭제
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 로딩 인디케이터 */}
|
||||
{isLoading && (
|
||||
<div className="fixed top-4 right-4 bg-white/20 backdrop-blur-sm rounded-full px-4 py-2 text-white text-sm z-40">
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||
처리 중...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 외부 클릭시 드롭다운 닫기 */}
|
||||
{showColumnDropdown && (
|
||||
<div
|
||||
className="fixed inset-0 z-10"
|
||||
onClick={() => setShowColumnDropdown(false)}
|
||||
></div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
// TestApp.jsx - React Test Component for GroupWare
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function TestApp() {
|
||||
const [status, setStatus] = useState('loading');
|
||||
const [counter, setCounter] = useState(0);
|
||||
const [serverTime, setServerTime] = useState('');
|
||||
const [apiTest, setApiTest] = useState({ status: 'pending', message: '' });
|
||||
|
||||
// 컴포넌트가 마운트될 때 실행
|
||||
useEffect(() => {
|
||||
// React가 정상적으로 로드되었음을 표시
|
||||
setTimeout(() => {
|
||||
setStatus('success');
|
||||
setServerTime(new Date().toLocaleString('ko-KR'));
|
||||
}, 1000);
|
||||
|
||||
// API 테스트
|
||||
testAPI();
|
||||
}, []);
|
||||
|
||||
// GroupWare API 테스트 함수
|
||||
const testAPI = async () => {
|
||||
try {
|
||||
// Home 컨트롤러 테스트
|
||||
const response = await fetch('/Home');
|
||||
if (response.ok) {
|
||||
setApiTest({ status: 'success', message: 'API 연결 성공' });
|
||||
} else {
|
||||
setApiTest({ status: 'warning', message: `API 응답: ${response.status}` });
|
||||
}
|
||||
} catch (error) {
|
||||
setApiTest({ status: 'error', message: `API 오류: ${error.message}` });
|
||||
}
|
||||
};
|
||||
|
||||
const buttonStyle = {
|
||||
padding: '10px 20px',
|
||||
margin: '5px',
|
||||
border: 'none',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer',
|
||||
fontSize: '14px'
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`status ${status === 'success' ? 'success' : 'loading'}`}>
|
||||
{status === 'success' ? (
|
||||
<div>
|
||||
<h3>✅ React 컴포넌트가 성공적으로 로드되었습니다!</h3>
|
||||
<p><strong>현재 시간:</strong> {serverTime}</p>
|
||||
<p><strong>파일 위치:</strong> /react/TestApp.jsx</p>
|
||||
</div>
|
||||
) : (
|
||||
<h3>React 컴포넌트를 로딩 중입니다...</h3>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{status === 'success' && (
|
||||
<div>
|
||||
<div className="status">
|
||||
<h3>📊 상태 관리 테스트</h3>
|
||||
<p><strong>카운터:</strong> {counter}</p>
|
||||
<button
|
||||
onClick={() => setCounter(counter + 1)}
|
||||
style={{
|
||||
...buttonStyle,
|
||||
backgroundColor: '#007bff',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
증가 (+1)
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCounter(counter - 1)}
|
||||
style={{
|
||||
...buttonStyle,
|
||||
backgroundColor: '#dc3545',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
감소 (-1)
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCounter(0)}
|
||||
style={{
|
||||
...buttonStyle,
|
||||
backgroundColor: '#6c757d',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
리셋
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={`status ${
|
||||
apiTest.status === 'success' ? 'success' :
|
||||
apiTest.status === 'error' ? 'error' : 'loading'
|
||||
}`}>
|
||||
<h3>🌐 GroupWare API 연결 테스트</h3>
|
||||
<p><strong>상태:</strong> {apiTest.message}</p>
|
||||
<p><strong>테스트 엔드포인트:</strong> /Home</p>
|
||||
<button
|
||||
onClick={testAPI}
|
||||
style={{
|
||||
...buttonStyle,
|
||||
backgroundColor: '#28a745',
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
API 다시 테스트
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="status">
|
||||
<h3>📋 React + OWIN 통합 테스트 체크리스트</h3>
|
||||
<ul style={{ textAlign: 'left' }}>
|
||||
<li>✅ OWIN 정적 파일 서빙</li>
|
||||
<li>✅ React 라이브러리 로딩 (CDN)</li>
|
||||
<li>✅ JSX 파일 분리 및 로딩</li>
|
||||
<li>✅ JSX 컴파일 (Babel)</li>
|
||||
<li>✅ React Hooks (useState, useEffect)</li>
|
||||
<li>✅ 이벤트 핸들링</li>
|
||||
<li>✅ API 호출 (fetch)</li>
|
||||
<li>✅ 반응형 UI 업데이트</li>
|
||||
<li>✅ 컴포넌트 모듈화</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="status success">
|
||||
<h3>🎉 통합 테스트 결과</h3>
|
||||
<p>GroupWare + OWIN + React 환경이 성공적으로 구성되었습니다!</p>
|
||||
<p><strong>다음 단계:</strong></p>
|
||||
<ul style={{ textAlign: 'left' }}>
|
||||
<li>React Router 추가 (SPA 라우팅)</li>
|
||||
<li>상태 관리 라이브러리 추가 (Redux/Zustand)</li>
|
||||
<li>UI 컴포넌트 라이브러리 추가 (Material-UI/Ant Design)</li>
|
||||
<li>번들링 도구 설정 (Webpack/Vite)</li>
|
||||
<li>TypeScript 지원 추가</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,811 +0,0 @@
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function Todo() {
|
||||
// 상태 관리
|
||||
const [todos, setTodos] = useState([]);
|
||||
const [activeTodos, setActiveTodos] = useState([]);
|
||||
const [completedTodos, setCompletedTodos] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [currentTab, setCurrentTab] = useState('active');
|
||||
const [currentEditId, setCurrentEditId] = useState(null);
|
||||
|
||||
// 모달 상태
|
||||
const [showAddModal, setShowAddModal] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
|
||||
// 폼 상태
|
||||
const [todoForm, setTodoForm] = useState({
|
||||
title: '',
|
||||
remark: '',
|
||||
expire: '',
|
||||
seqno: 0,
|
||||
flag: false,
|
||||
request: '',
|
||||
status: '0'
|
||||
});
|
||||
|
||||
const [editForm, setEditForm] = useState({
|
||||
idx: 0,
|
||||
title: '',
|
||||
remark: '',
|
||||
expire: '',
|
||||
seqno: 0,
|
||||
flag: false,
|
||||
request: '',
|
||||
status: '0'
|
||||
});
|
||||
|
||||
// 컴포넌트 마운트시 할일 목록 로드
|
||||
useEffect(() => {
|
||||
loadTodos();
|
||||
}, []);
|
||||
|
||||
// 할일 목록을 활성/완료로 분리
|
||||
useEffect(() => {
|
||||
const active = todos.filter(todo => (todo.status || '0') !== '5');
|
||||
const completed = todos.filter(todo => (todo.status || '0') === '5');
|
||||
setActiveTodos(active);
|
||||
setCompletedTodos(completed);
|
||||
}, [todos]);
|
||||
|
||||
// 할일 목록 로드
|
||||
const loadTodos = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Todo/GetTodos');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
setTodos(data.Data || []);
|
||||
} else {
|
||||
showNotification(data.Message || '할일 목록을 불러올 수 없습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('할일 목록 로드 중 오류:', error);
|
||||
showNotification('서버 연결에 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 새 할일 추가
|
||||
const addTodo = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!todoForm.remark.trim()) {
|
||||
showNotification('할일 내용을 입력해주세요.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Todo/CreateTodo', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...todoForm,
|
||||
seqno: parseInt(todoForm.seqno),
|
||||
expire: todoForm.expire || null,
|
||||
request: todoForm.request || null
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
setShowAddModal(false);
|
||||
setTodoForm({
|
||||
title: '',
|
||||
remark: '',
|
||||
expire: '',
|
||||
seqno: 0,
|
||||
flag: false,
|
||||
request: '',
|
||||
status: '0'
|
||||
});
|
||||
loadTodos();
|
||||
showNotification(data.Message || '할일이 추가되었습니다.', 'success');
|
||||
} else {
|
||||
showNotification(data.Message || '할일 추가에 실패했습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('할일 추가 중 오류:', error);
|
||||
showNotification('서버 연결에 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 할일 수정
|
||||
const updateTodo = async () => {
|
||||
if (!editForm.remark.trim()) {
|
||||
showNotification('할일 내용을 입력해주세요.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Todo/UpdateTodo', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...editForm,
|
||||
seqno: parseInt(editForm.seqno),
|
||||
expire: editForm.expire || null,
|
||||
request: editForm.request || null
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
setShowEditModal(false);
|
||||
setCurrentEditId(null);
|
||||
loadTodos();
|
||||
showNotification(data.Message || '할일이 수정되었습니다.', 'success');
|
||||
} else {
|
||||
showNotification(data.Message || '할일 수정에 실패했습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('할일 수정 중 오류:', error);
|
||||
showNotification('서버 연결에 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 상태 업데이트 (편집 모달에서 바로 서버에 반영)
|
||||
const updateTodoStatus = async (status) => {
|
||||
if (!currentEditId) return;
|
||||
|
||||
const formData = {
|
||||
...editForm,
|
||||
status: status,
|
||||
seqno: parseInt(editForm.seqno),
|
||||
expire: editForm.expire || null,
|
||||
request: editForm.request || null
|
||||
};
|
||||
|
||||
if (!formData.remark.trim()) {
|
||||
showNotification('할일 내용을 입력해주세요.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch('/Todo/UpdateTodo', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
setShowEditModal(false);
|
||||
setCurrentEditId(null);
|
||||
loadTodos();
|
||||
showNotification(`상태가 '${getStatusText(status)}'(으)로 변경되었습니다.`, 'success');
|
||||
} else {
|
||||
showNotification(data.Message || '상태 변경에 실패했습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('상태 변경 중 오류:', error);
|
||||
showNotification('서버 연결에 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 할일 편집 모달 열기
|
||||
const editTodo = async (id) => {
|
||||
setCurrentEditId(id);
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch(`/Todo/GetTodo?id=${id}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success && data.Data) {
|
||||
const todo = data.Data;
|
||||
setEditForm({
|
||||
idx: todo.idx,
|
||||
title: todo.title || '',
|
||||
remark: todo.remark || '',
|
||||
expire: todo.expire ? new Date(todo.expire).toISOString().split('T')[0] : '',
|
||||
seqno: todo.seqno || 0,
|
||||
flag: todo.flag || false,
|
||||
request: todo.request || '',
|
||||
status: todo.status || '0'
|
||||
});
|
||||
setShowEditModal(true);
|
||||
} else {
|
||||
showNotification(data.Message || '할일 정보를 불러올 수 없습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('할일 조회 중 오류:', error);
|
||||
showNotification('서버 연결에 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 할일 삭제
|
||||
const deleteTodo = async (id) => {
|
||||
if (!confirm('정말로 이 할일을 삭제하시겠습니까?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/Todo/DeleteTodo?id=${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.Success) {
|
||||
loadTodos();
|
||||
showNotification(data.Message || '할일이 삭제되었습니다.', 'success');
|
||||
} else {
|
||||
showNotification(data.Message || '할일 삭제에 실패했습니다.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('할일 삭제 중 오류:', error);
|
||||
showNotification('서버 연결에 실패했습니다.', 'error');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 유틸리티 함수들
|
||||
const getStatusClass = (status) => {
|
||||
switch(status) {
|
||||
case '0': return 'bg-gray-500/20 text-gray-300';
|
||||
case '1': return 'bg-primary-500/20 text-primary-300';
|
||||
case '2': return 'bg-danger-500/20 text-danger-300';
|
||||
case '3': return 'bg-warning-500/20 text-warning-300';
|
||||
case '5': return 'bg-success-500/20 text-success-300';
|
||||
default: return 'bg-white/10 text-white/50';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = (status) => {
|
||||
switch(status) {
|
||||
case '0': return '대기';
|
||||
case '1': return '진행';
|
||||
case '2': return '취소';
|
||||
case '3': return '보류';
|
||||
case '5': return '완료';
|
||||
default: return '대기';
|
||||
}
|
||||
};
|
||||
|
||||
const getSeqnoClass = (seqno) => {
|
||||
switch(seqno) {
|
||||
case 1: return 'bg-primary-500/20 text-primary-300';
|
||||
case 2: return 'bg-warning-500/20 text-warning-300';
|
||||
case 3: return 'bg-danger-500/20 text-danger-300';
|
||||
default: return 'bg-white/10 text-white/50';
|
||||
}
|
||||
};
|
||||
|
||||
const getSeqnoText = (seqno) => {
|
||||
switch(seqno) {
|
||||
case 1: return '중요';
|
||||
case 2: return '매우 중요';
|
||||
case 3: return '긴급';
|
||||
default: return '보통';
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return '-';
|
||||
return new Date(dateString).toLocaleDateString('ko-KR');
|
||||
};
|
||||
|
||||
// 알림 표시 함수
|
||||
const showNotification = (message, type = 'info') => {
|
||||
const colors = {
|
||||
info: 'bg-blue-500/90 backdrop-blur-sm',
|
||||
success: 'bg-green-500/90 backdrop-blur-sm',
|
||||
warning: 'bg-yellow-500/90 backdrop-blur-sm',
|
||||
error: 'bg-red-500/90 backdrop-blur-sm'
|
||||
};
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 ${colors[type]} text-white px-4 py-3 rounded-lg z-50 transition-all duration-300 transform translate-x-0 opacity-100 shadow-lg border border-white/20`;
|
||||
notification.innerHTML = `
|
||||
<div class="flex items-center">
|
||||
<span class="ml-2">${message}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(0)';
|
||||
notification.style.opacity = '1';
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.style.transform = 'translateX(100%)';
|
||||
notification.style.opacity = '0';
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// 할일 행 렌더링
|
||||
const renderTodoRow = (todo, includeOkdate = false) => {
|
||||
const statusClass = getStatusClass(todo.status);
|
||||
const statusText = getStatusText(todo.status);
|
||||
|
||||
const flagClass = todo.flag ? 'bg-warning-500/20 text-warning-300' : 'bg-white/10 text-white/50';
|
||||
const flagText = todo.flag ? '고정' : '일반';
|
||||
|
||||
const seqnoClass = getSeqnoClass(todo.seqno);
|
||||
const seqnoText = getSeqnoText(todo.seqno);
|
||||
|
||||
const expireText = formatDate(todo.expire);
|
||||
const isExpired = todo.expire && new Date(todo.expire) < new Date();
|
||||
const expireClass = isExpired ? 'text-danger-400' : 'text-white/80';
|
||||
|
||||
const okdateText = formatDate(todo.okdate);
|
||||
const okdateClass = todo.okdate ? 'text-success-400' : 'text-white/80';
|
||||
|
||||
return (
|
||||
<tr key={todo.idx} className="hover:bg-white/5 transition-colors cursor-pointer" onClick={() => editTodo(todo.idx)}>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${statusClass}`}>
|
||||
{statusText}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${flagClass}`}>
|
||||
{flagText}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-white">{todo.title || '제목 없음'}</td>
|
||||
<td className="px-6 py-4 text-white/80 max-w-xs truncate">{todo.remark || ''}</td>
|
||||
<td className="px-6 py-4 text-white/80">{todo.request || '-'}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${seqnoClass}`}>
|
||||
{seqnoText}
|
||||
</span>
|
||||
</td>
|
||||
<td className={`px-6 py-4 whitespace-nowrap ${expireClass}`}>{expireText}</td>
|
||||
{includeOkdate && <td className={`px-6 py-4 whitespace-nowrap ${okdateClass}`}>{okdateText}</td>}
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm" onClick={(e) => e.stopPropagation()}>
|
||||
<button onClick={() => editTodo(todo.idx)} className="text-primary-400 hover:text-primary-300 mr-3 transition-colors">
|
||||
수정
|
||||
</button>
|
||||
<button onClick={() => deleteTodo(todo.idx)} className="text-danger-400 hover:text-danger-300 transition-colors">
|
||||
삭제
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
{/* 할일 목록 */}
|
||||
<div className="glass-effect rounded-2xl overflow-hidden animate-slide-up">
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
</svg>
|
||||
내 할일 목록
|
||||
</h2>
|
||||
<button onClick={() => setShowAddModal(true)} className="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-lg transition-colors flex items-center text-sm">
|
||||
<svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
새 할일 추가
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 탭 메뉴 */}
|
||||
<div className="px-6 py-2 border-b border-white/10">
|
||||
<div className="flex space-x-1 bg-white/5 rounded-lg p-1">
|
||||
<button onClick={() => setCurrentTab('active')} className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${
|
||||
currentTab === 'active'
|
||||
? 'text-white bg-white/20 shadow-sm'
|
||||
: 'text-white/60 hover:text-white hover:bg-white/10'
|
||||
}`}>
|
||||
<div className="flex items-center justify-center space-x-2">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
<span>진행중인 할일</span>
|
||||
<span className="px-2 py-0.5 text-xs bg-primary-500/30 text-primary-200 rounded-full">{activeTodos.length}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button onClick={() => setCurrentTab('completed')} className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 ${
|
||||
currentTab === 'completed'
|
||||
? 'text-white bg-white/20 shadow-sm'
|
||||
: 'text-white/60 hover:text-white hover:bg-white/10'
|
||||
}`}>
|
||||
<div className="flex items-center justify-center space-x-2">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span>완료된 할일</span>
|
||||
<span className="px-2 py-0.5 text-xs bg-success-500/30 text-success-200 rounded-full">{completedTodos.length}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 진행중인 할일 테이블 */}
|
||||
{currentTab === 'active' && (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead className="bg-white/10">
|
||||
<tr>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">진행상태</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">플래그</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">제목</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">내용</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">요청자</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">중요도</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">만료일</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">작업</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{isLoading ? (
|
||||
<tr>
|
||||
<td colSpan="8" className="p-8 text-center">
|
||||
<div className="inline-flex items-center">
|
||||
<div className="loading inline-block w-5 h-5 border-3 border-white/30 border-t-white rounded-full animate-spin mr-3"></div>
|
||||
<span className="text-white/80">데이터를 불러오는 중...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : activeTodos.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="8" className="px-6 py-8 text-center text-white/50">
|
||||
진행중인 할일이 없습니다
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
activeTodos.map(todo => renderTodoRow(todo, false))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 완료된 할일 테이블 */}
|
||||
{currentTab === 'completed' && (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead className="bg-white/10">
|
||||
<tr>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">진행상태</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">플래그</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">제목</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">내용</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">요청자</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">중요도</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">만료일</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">완료일</th>
|
||||
<th className="px-6 py-4 text-left text-xs font-medium text-white/70 uppercase tracking-wider">작업</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-white/10">
|
||||
{isLoading ? (
|
||||
<tr>
|
||||
<td colSpan="9" className="p-8 text-center">
|
||||
<div className="inline-flex items-center">
|
||||
<div className="loading inline-block w-5 h-5 border-3 border-white/30 border-t-white rounded-full animate-spin mr-3"></div>
|
||||
<span className="text-white/80">데이터를 불러오는 중...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : completedTodos.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan="9" className="px-6 py-8 text-center text-white/50">
|
||||
완료된 할일이 없습니다
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
completedTodos.map(todo => renderTodoRow(todo, true))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 로딩 인디케이터 */}
|
||||
{isLoading && (
|
||||
<div className="fixed top-4 right-4 bg-white/20 backdrop-blur-sm rounded-full px-4 py-2 text-white text-sm">
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
|
||||
처리 중...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 새 할일 추가 모달 */}
|
||||
{showAddModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-2xl animate-slide-up">
|
||||
{/* 모달 헤더 */}
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
새 할일 추가
|
||||
</h2>
|
||||
<button onClick={() => setShowAddModal(false)} className="text-white/70 hover:text-white transition-colors">
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 모달 내용 */}
|
||||
<div className="p-6">
|
||||
<form onSubmit={addTodo} className="space-y-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">제목 (선택사항)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={todoForm.title}
|
||||
onChange={(e) => setTodoForm({...todoForm, title: e.target.value})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="할일 제목을 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">만료일 (선택사항)</label>
|
||||
<input
|
||||
type="date"
|
||||
value={todoForm.expire}
|
||||
onChange={(e) => setTodoForm({...todoForm, expire: e.target.value})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">내용 *</label>
|
||||
<textarea
|
||||
value={todoForm.remark}
|
||||
onChange={(e) => setTodoForm({...todoForm, remark: e.target.value})}
|
||||
rows="3"
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="할일 내용을 입력하세요 (필수)"
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">요청자</label>
|
||||
<input
|
||||
type="text"
|
||||
value={todoForm.request}
|
||||
onChange={(e) => setTodoForm({...todoForm, request: e.target.value})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="업무 요청자를 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">진행상태</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[
|
||||
{value: '0', label: '대기', class: 'bg-gray-500/20 text-gray-300'},
|
||||
{value: '1', label: '진행', class: 'bg-primary-500/20 text-primary-300'},
|
||||
{value: '3', label: '보류', class: 'bg-warning-500/20 text-warning-300'},
|
||||
{value: '2', label: '취소', class: 'bg-danger-500/20 text-danger-300'},
|
||||
{value: '5', label: '완료', class: 'bg-success-500/20 text-success-300'}
|
||||
].map(status => (
|
||||
<button
|
||||
key={status.value}
|
||||
type="button"
|
||||
onClick={() => setTodoForm({...todoForm, status: status.value})}
|
||||
className={`px-3 py-1 rounded-lg text-xs font-medium transition-all ${
|
||||
todoForm.status === status.value
|
||||
? status.class + ' border-' + status.class.split(' ')[0].replace('bg-', '').replace('/20', '/30')
|
||||
: 'bg-white/10 text-white/50 border border-white/20 hover:bg-white/20'
|
||||
}`}
|
||||
>
|
||||
{status.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">중요도</label>
|
||||
<select
|
||||
value={todoForm.seqno}
|
||||
onChange={(e) => setTodoForm({...todoForm, seqno: parseInt(e.target.value)})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
>
|
||||
<option value="0">보통</option>
|
||||
<option value="1">중요</option>
|
||||
<option value="2">매우 중요</option>
|
||||
<option value="3">긴급</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex items-end">
|
||||
<label className="flex items-center text-white/70 text-sm font-medium">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={todoForm.flag}
|
||||
onChange={(e) => setTodoForm({...todoForm, flag: e.target.checked})}
|
||||
className="mr-2 text-primary-500 focus:ring-primary-400 focus:ring-offset-0 rounded"
|
||||
/>
|
||||
플래그 (상단 고정)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{/* 모달 푸터 */}
|
||||
<div className="px-6 py-4 border-t border-white/10 flex justify-end space-x-3">
|
||||
<button type="button" onClick={() => setShowAddModal(false)} className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button type="submit" form="todoForm" onClick={addTodo} className="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors flex items-center">
|
||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
추가
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 수정 모달 */}
|
||||
{showEditModal && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50">
|
||||
<div className="flex items-center justify-center min-h-screen p-4">
|
||||
<div className="glass-effect rounded-2xl w-full max-w-2xl animate-slide-up">
|
||||
{/* 모달 헤더 */}
|
||||
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-white flex items-center">
|
||||
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||
</svg>
|
||||
할일 수정
|
||||
</h2>
|
||||
<button onClick={() => {setShowEditModal(false); setCurrentEditId(null);}} className="text-white/70 hover:text-white transition-colors">
|
||||
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 모달 내용 */}
|
||||
<div className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">제목 (선택사항)</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editForm.title}
|
||||
onChange={(e) => setEditForm({...editForm, title: e.target.value})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="할일 제목을 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">만료일 (선택사항)</label>
|
||||
<input
|
||||
type="date"
|
||||
value={editForm.expire}
|
||||
onChange={(e) => setEditForm({...editForm, expire: e.target.value})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">내용 *</label>
|
||||
<textarea
|
||||
value={editForm.remark}
|
||||
onChange={(e) => setEditForm({...editForm, remark: e.target.value})}
|
||||
rows="3"
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="할일 내용을 입력하세요 (필수)"
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">요청자</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editForm.request}
|
||||
onChange={(e) => setEditForm({...editForm, request: e.target.value})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
placeholder="업무 요청자를 입력하세요"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">진행상태</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[
|
||||
{value: '0', label: '대기', class: 'bg-gray-500/20 text-gray-300'},
|
||||
{value: '1', label: '진행', class: 'bg-primary-500/20 text-primary-300'},
|
||||
{value: '3', label: '보류', class: 'bg-warning-500/20 text-warning-300'},
|
||||
{value: '2', label: '취소', class: 'bg-danger-500/20 text-danger-300'},
|
||||
{value: '5', label: '완료', class: 'bg-success-500/20 text-success-300'}
|
||||
].map(status => (
|
||||
<button
|
||||
key={status.value}
|
||||
type="button"
|
||||
onClick={() => updateTodoStatus(status.value)}
|
||||
className={`px-3 py-1 rounded-lg text-xs font-medium transition-all ${
|
||||
editForm.status === status.value
|
||||
? status.class + ' border-' + status.class.split(' ')[0].replace('bg-', '').replace('/20', '/30')
|
||||
: 'bg-white/10 text-white/50 border border-white/20 hover:bg-white/20'
|
||||
}`}
|
||||
>
|
||||
{status.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-white/70 text-sm font-medium mb-2">중요도</label>
|
||||
<select
|
||||
value={editForm.seqno}
|
||||
onChange={(e) => setEditForm({...editForm, seqno: parseInt(e.target.value)})}
|
||||
className="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all"
|
||||
>
|
||||
<option value="0">보통</option>
|
||||
<option value="1">중요</option>
|
||||
<option value="2">매우 중요</option>
|
||||
<option value="3">긴급</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="flex items-center text-white/70 text-sm font-medium mt-6">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.flag}
|
||||
onChange={(e) => setEditForm({...editForm, flag: e.target.checked})}
|
||||
className="mr-2 text-primary-500 focus:ring-primary-400 focus:ring-offset-0 rounded"
|
||||
/>
|
||||
플래그 (상단 고정)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 모달 푸터 */}
|
||||
<div className="px-6 py-4 border-t border-white/10 flex justify-end space-x-3">
|
||||
<button onClick={() => {setShowEditModal(false); setCurrentEditId(null);}} className="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button onClick={updateTodo} className="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors">
|
||||
수정
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<title>공용코드관리 (React)</title>
|
||||
<link rel="stylesheet" href="/lib/css/tailwind.min.css">
|
||||
<script src="/lib/js/tailwind-config.js"></script>
|
||||
|
||||
<!-- Tailwind 설정 -->
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
},
|
||||
success: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
},
|
||||
warning: {
|
||||
50: '#fffbeb',
|
||||
100: '#fef3c7',
|
||||
200: '#fde68a',
|
||||
300: '#fcd34d',
|
||||
400: '#fbbf24',
|
||||
500: '#f59e0b',
|
||||
600: '#d97706',
|
||||
700: '#b45309',
|
||||
800: '#92400e',
|
||||
900: '#78350f',
|
||||
},
|
||||
danger: {
|
||||
50: '#fef2f2',
|
||||
100: '#fee2e2',
|
||||
200: '#fecaca',
|
||||
300: '#fca5a5',
|
||||
400: '#f87171',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
800: '#991b1b',
|
||||
900: '#7f1d1d',
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
'fade-in': 'fadeIn 0.5s ease-in-out',
|
||||
'slide-up': 'slideUp 0.3s ease-out',
|
||||
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
},
|
||||
keyframes: {
|
||||
fadeIn: {
|
||||
'0%': { opacity: '0' },
|
||||
'100%': { opacity: '1' },
|
||||
},
|
||||
slideUp: {
|
||||
'0%': { transform: 'translateY(10px)', opacity: '0' },
|
||||
'100%': { transform: 'translateY(0)', opacity: '1' },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.gradient-bg {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* 스크롤바 스타일링 */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 애니메이션 */
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.animate-slide-up {
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* 셀렉트 박스 옵션 스타일링 */
|
||||
select option {
|
||||
background-color: #374151 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
select option:hover {
|
||||
background-color: #4B5563 !important;
|
||||
}
|
||||
|
||||
select option:checked {
|
||||
background-color: #6366F1 !important;
|
||||
}
|
||||
|
||||
/* 테이블 셀 텍스트 오버플로우 처리 */
|
||||
.truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 값(문자열) 열 최대 너비 제한 */
|
||||
.svalue-cell {
|
||||
max-width: 128px; /* w-32 = 128px */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 개발중 경고 스타일 */
|
||||
.dev-warning {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background: linear-gradient(135deg, #fbbf24, #f59e0b);
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(245, 158, 11, 0.3);
|
||||
z-index: 1000;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.dev-warning .icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dev-warning .title {
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dev-warning .description {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<!-- 로딩 스켈레톤 UI -->
|
||||
<div id="react-common-app" class="animate-fade-in">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex gap-6 h-[calc(100vh-200px)]">
|
||||
<!-- 좌측 스켈레톤 -->
|
||||
<div class="w-80">
|
||||
<div class="glass-effect rounded-2xl h-full animate-pulse">
|
||||
<div class="p-4 border-b border-white/10">
|
||||
<div class="h-6 bg-white/20 rounded w-3/4"></div>
|
||||
</div>
|
||||
<div class="p-4 space-y-3">
|
||||
<div class="h-16 bg-white/10 rounded-lg"></div>
|
||||
<div class="h-16 bg-white/10 rounded-lg"></div>
|
||||
<div class="h-16 bg-white/10 rounded-lg"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 우측 스켈레톤 -->
|
||||
<div class="flex-1">
|
||||
<div class="glass-effect rounded-2xl h-full animate-pulse">
|
||||
<div class="p-4 border-b border-white/10 flex justify-between items-center">
|
||||
<div class="h-6 bg-white/20 rounded w-1/3"></div>
|
||||
<div class="h-8 bg-white/20 rounded w-20"></div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="space-y-3">
|
||||
<div class="h-10 bg-white/10 rounded"></div>
|
||||
<div class="h-10 bg-white/10 rounded"></div>
|
||||
<div class="h-10 bg-white/10 rounded"></div>
|
||||
<div class="h-10 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React Local -->
|
||||
<script crossorigin src="/lib/js/react.development.js"></script>
|
||||
<script crossorigin src="/lib/js/react-dom.development.js"></script>
|
||||
<script src="/lib/js/babel.min.js"></script>
|
||||
|
||||
<!-- 공통 네비게이션 컴포넌트 -->
|
||||
<script type="text/babel" src="/react/component/CommonNavigation"></script>
|
||||
|
||||
<!-- 개발중 경고 컴포넌트 -->
|
||||
<script type="text/babel" src="/react/component/DevWarning"></script>
|
||||
|
||||
<!-- App 컴포넌트 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<CommonNavigation currentPage="common" />
|
||||
<CommonCode />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 공용코드 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/CommonCode"></script>
|
||||
|
||||
<!-- 앱 초기화 -->
|
||||
<script type="text/babel">
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-common-app'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,297 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<meta name="version" content="v2.0-20250905-react">
|
||||
<title>근태현황 대시보드 (React)</title>
|
||||
<link rel="stylesheet" href="/lib/css/tailwind.min.css">
|
||||
<script src="/lib/js/tailwind-config.js"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
},
|
||||
success: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
},
|
||||
warning: {
|
||||
50: '#fffbeb',
|
||||
100: '#fef3c7',
|
||||
200: '#fde68a',
|
||||
300: '#fcd34d',
|
||||
400: '#fbbf24',
|
||||
500: '#f59e0b',
|
||||
600: '#d97706',
|
||||
700: '#b45309',
|
||||
800: '#92400e',
|
||||
900: '#78350f',
|
||||
},
|
||||
danger: {
|
||||
50: '#fef2f2',
|
||||
100: '#fee2e2',
|
||||
200: '#fecaca',
|
||||
300: '#fca5a5',
|
||||
400: '#f87171',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
800: '#991b1b',
|
||||
900: '#7f1d1d',
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
'fade-in': 'fadeIn 0.5s ease-in-out',
|
||||
'slide-up': 'slideUp 0.3s ease-out',
|
||||
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
},
|
||||
keyframes: {
|
||||
fadeIn: {
|
||||
'0%': { opacity: '0' },
|
||||
'100%': { opacity: '1' },
|
||||
},
|
||||
slideUp: {
|
||||
'0%': { transform: 'translateY(10px)', opacity: '0' },
|
||||
'100%': { transform: 'translateY(0)', opacity: '1' },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.gradient-bg {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* 스크롤바 스타일링 */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* React 컴포넌트 로딩 스타일 */
|
||||
.react-dashboard-container {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.loading-skeleton {
|
||||
background: linear-gradient(90deg, rgba(255,255,255,0.1) 25%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.1) 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: loading 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="react-dashboard-app" class="react-dashboard-container">
|
||||
<!-- 로딩 화면 -->
|
||||
<div class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<!-- 로딩 헤더 -->
|
||||
<div class="text-center mb-8">
|
||||
<div class="loading-skeleton h-10 w-80 mx-auto rounded-lg mb-4"></div>
|
||||
<div class="loading-skeleton h-6 w-60 mx-auto rounded-lg mb-2"></div>
|
||||
<div class="loading-skeleton h-4 w-40 mx-auto rounded-lg"></div>
|
||||
</div>
|
||||
|
||||
<!-- 로딩 통계 카드들 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mb-8">
|
||||
<div class="glass-effect rounded-2xl p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="loading-skeleton h-4 w-16 rounded mb-2"></div>
|
||||
<div class="loading-skeleton h-8 w-12 rounded"></div>
|
||||
</div>
|
||||
<div class="w-12 h-12 bg-success-500/20 rounded-full flex items-center justify-center">
|
||||
<div class="loading-skeleton w-6 h-6 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass-effect rounded-2xl p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="loading-skeleton h-4 w-16 rounded mb-2"></div>
|
||||
<div class="loading-skeleton h-8 w-12 rounded"></div>
|
||||
</div>
|
||||
<div class="w-12 h-12 bg-warning-500/20 rounded-full flex items-center justify-center">
|
||||
<div class="loading-skeleton w-6 h-6 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass-effect rounded-2xl p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="loading-skeleton h-4 w-16 rounded mb-2"></div>
|
||||
<div class="loading-skeleton h-8 w-12 rounded"></div>
|
||||
</div>
|
||||
<div class="w-12 h-12 bg-primary-500/20 rounded-full flex items-center justify-center">
|
||||
<div class="loading-skeleton w-6 h-6 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass-effect rounded-2xl p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="loading-skeleton h-4 w-20 rounded mb-2"></div>
|
||||
<div class="loading-skeleton h-8 w-12 rounded"></div>
|
||||
</div>
|
||||
<div class="w-12 h-12 bg-danger-500/20 rounded-full flex items-center justify-center">
|
||||
<div class="loading-skeleton w-6 h-6 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass-effect rounded-2xl p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="loading-skeleton h-4 w-20 rounded mb-2"></div>
|
||||
<div class="loading-skeleton h-8 w-12 rounded"></div>
|
||||
</div>
|
||||
<div class="w-12 h-12 bg-purple-500/20 rounded-full flex items-center justify-center">
|
||||
<div class="loading-skeleton w-6 h-6 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 로딩 추가 정보 -->
|
||||
<div class="glass-effect rounded-2xl p-6">
|
||||
<div class="loading-skeleton h-8 w-32 rounded mb-4"></div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="text-center">
|
||||
<div class="w-16 h-16 bg-success-500/20 rounded-full mx-auto mb-2">
|
||||
<div class="loading-skeleton w-full h-full rounded-full"></div>
|
||||
</div>
|
||||
<div class="loading-skeleton h-4 w-16 rounded mx-auto mb-1"></div>
|
||||
<div class="loading-skeleton h-3 w-24 rounded mx-auto"></div>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="w-16 h-16 bg-warning-500/20 rounded-full mx-auto mb-2">
|
||||
<div class="loading-skeleton w-full h-full rounded-full"></div>
|
||||
</div>
|
||||
<div class="loading-skeleton h-4 w-16 rounded mx-auto mb-1"></div>
|
||||
<div class="loading-skeleton h-3 w-24 rounded mx-auto"></div>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="w-16 h-16 bg-primary-500/20 rounded-full mx-auto mb-2">
|
||||
<div class="loading-skeleton w-full h-full rounded-full"></div>
|
||||
</div>
|
||||
<div class="loading-skeleton h-4 w-16 rounded mx-auto mb-1"></div>
|
||||
<div class="loading-skeleton h-3 w-24 rounded mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 로딩 텍스트 -->
|
||||
<div class="text-center mt-8">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-white mx-auto mb-4"></div>
|
||||
<p class="text-white/70">React Dashboard 컴포넌트를 로딩 중입니다...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React Local -->
|
||||
<script crossorigin src="/lib/js/react.development.js"></script>
|
||||
<script crossorigin src="/lib/js/react-dom.development.js"></script>
|
||||
<script src="/lib/js/babel.min.js"></script>
|
||||
|
||||
<!-- 공통 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/CommonNavigation"></script>
|
||||
<script type="text/babel" src="/react/component/DevWarning"></script>
|
||||
|
||||
<!-- Dashboard 컴포넌트 -->
|
||||
<script type="text/babel" src="/react/component/DashboardApp"></script>
|
||||
|
||||
<!-- 앱 초기화 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
console.log('✅ App 컴포넌트 렌더링 시작');
|
||||
console.log('📊 CommonNavigation 사용 가능:', typeof CommonNavigation);
|
||||
console.log('📊 DashboardApp 사용 가능:', typeof DashboardApp);
|
||||
console.log('📊 DevWarning 사용 가능:', typeof DevWarning);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CommonNavigation currentPage="dashboard" />
|
||||
<DashboardApp />
|
||||
<DevWarning show={false} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 루트 렌더링
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-dashboard-app'));
|
||||
root.render(<App />);
|
||||
|
||||
console.log('✅ React Dashboard 앱이 마운트되었습니다.');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,261 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<title>업무일지 (React)</title>
|
||||
<link rel="stylesheet" href="/lib/css/tailwind.min.css">
|
||||
<script src="/lib/js/tailwind-config.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.gradient-bg {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
/* 스크롤바 스타일링 */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 애니메이션 */
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.animate-slide-up {
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* 셀렉트 박스 옵션 스타일링 */
|
||||
select option {
|
||||
background-color: #374151 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
select option:hover {
|
||||
background-color: #4B5563 !important;
|
||||
}
|
||||
|
||||
select option:checked {
|
||||
background-color: #6366F1 !important;
|
||||
}
|
||||
|
||||
/* 개발중 경고 스타일 */
|
||||
.dev-warning {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background: linear-gradient(135deg, #fbbf24, #f59e0b);
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(245, 158, 11, 0.3);
|
||||
z-index: 1000;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.dev-warning .icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dev-warning .title {
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dev-warning .description {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<!-- 로딩 스켈레톤 UI -->
|
||||
<div id="react-jobreport-app" class="animate-fade-in">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
{/* 스켈레톤 UI */}
|
||||
<div className="space-y-6">
|
||||
{/* 경고 메시지 스켈레톤 */}
|
||||
<div className="bg-white/10 rounded-lg p-4 animate-pulse">
|
||||
<div className="h-6 bg-white/20 rounded w-3/4"></div>
|
||||
</div>
|
||||
|
||||
{/* 통계 카드 스켈레톤 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div className="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div className="flex items-center">
|
||||
<div className="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div className="h-4 bg-white/20 rounded w-20 mb-2"></div>
|
||||
<div className="h-6 bg-white/20 rounded w-12"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div className="flex items-center">
|
||||
<div className="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div className="h-4 bg-white/20 rounded w-24 mb-2"></div>
|
||||
<div className="h-6 bg-white/20 rounded w-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div className="flex items-center">
|
||||
<div className="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div className="h-4 bg-white/20 rounded w-20 mb-2"></div>
|
||||
<div className="h-6 bg-white/20 rounded w-14"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div className="flex items-center">
|
||||
<div className="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div className="h-4 bg-white/20 rounded w-28 mb-2"></div>
|
||||
<div className="h-6 bg-white/20 rounded w-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 필터 스켈레톤 */}
|
||||
<div className="glass-effect rounded-lg p-4 animate-pulse">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="col-span-2 space-y-3">
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="h-8 bg-white/10 rounded"></div>
|
||||
<div className="h-8 bg-white/10 rounded"></div>
|
||||
<div className="h-8 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="h-8 bg-white/10 rounded"></div>
|
||||
<div className="h-8 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="h-10 bg-white/10 rounded"></div>
|
||||
<div className="h-10 bg-white/10 rounded"></div>
|
||||
<div className="h-10 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 테이블 스켈레톤 */}
|
||||
<div className="glass-effect rounded-lg p-4 animate-pulse">
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-7 gap-4">
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
<div className="h-6 bg-white/20 rounded"></div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="grid grid-cols-7 gap-4">
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
<div className="grid grid-cols-7 gap-4">
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
<div className="grid grid-cols-7 gap-4">
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
<div className="h-4 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React Local -->
|
||||
<script crossorigin src="/lib/js/react.development.js"></script>
|
||||
<script crossorigin src="/lib/js/react-dom.development.js"></script>
|
||||
<script src="/lib/js/babel.min.js"></script>
|
||||
|
||||
<!-- 공통 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/CommonNavigation"></script>
|
||||
<script type="text/babel" src="/react/component/DevWarning"></script>
|
||||
|
||||
<!-- 앱 컴포넌트 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<CommonNavigation currentPage="jobreport" />
|
||||
<JobReport />
|
||||
<DevWarning />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 업무일지 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/JobReport"></script>
|
||||
|
||||
<!-- 앱 초기화 -->
|
||||
<script type="text/babel">
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-jobreport-app'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,120 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>React JSX Test - GroupWare</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
.header h1 {
|
||||
color: #333;
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
.header p {
|
||||
color: #666;
|
||||
font-size: 1.2em;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.status {
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.success {
|
||||
background-color: #d4edda;
|
||||
border: 1px solid #c3e6cb;
|
||||
color: #155724;
|
||||
}
|
||||
.loading {
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
color: #856404;
|
||||
}
|
||||
.error {
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
color: #721c24;
|
||||
}
|
||||
.tech-info {
|
||||
background-color: #e3f2fd;
|
||||
border: 1px solid #90caf9;
|
||||
color: #0d47a1;
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.version-info {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
padding: 15px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🚀 React JSX Integration</h1>
|
||||
<p>GroupWare + OWIN + React + JSX 모듈화 테스트</p>
|
||||
<div class="tech-info">
|
||||
<strong>기술 스택:</strong> C# WinForms + OWIN + React 18 + Babel JSX + 모듈화된 컴포넌트
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="react-app">
|
||||
<div class="status loading">
|
||||
React JSX 컴포넌트를 로딩 중입니다...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="version-info">
|
||||
<p><strong>환경:</strong> .NET Framework 4.6 + OWIN + React 18.2.0</p>
|
||||
<p><strong>포트:</strong> 7979 | <strong>파일 위치:</strong> /react-jsx-test.html</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React & ReactDOM CDN -->
|
||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
||||
<!-- Babel standalone for JSX -->
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
|
||||
<!-- JSX Component Import -->
|
||||
<script type="text/babel" src="/react/component/TestApp"></script>
|
||||
|
||||
<!-- App Initialization -->
|
||||
<script type="text/babel">
|
||||
// JSX 컴포넌트를 DOM에 렌더링
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-app'));
|
||||
root.render(<TestApp />);
|
||||
|
||||
console.log('✅ React JSX 컴포넌트가 성공적으로 마운트되었습니다.');
|
||||
console.log('📁 컴포넌트 파일: /react/TestApp.jsx');
|
||||
console.log('🌐 테스트 페이지: /react-jsx-test.html');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,241 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<title>근태관리 (React)</title>
|
||||
<link rel="stylesheet" href="/lib/css/tailwind.min.css">
|
||||
<script src="/lib/js/tailwind-config.js"></script>
|
||||
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.gradient-bg {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-top: 3px solid #ffffff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.table-container {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 스크롤바 스타일링 */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 애니메이션 */
|
||||
.animate-fade-in {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.animate-slide-up {
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* 개발중 경고 스타일 */
|
||||
.dev-warning {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
background: linear-gradient(135deg, #fbbf24, #f59e0b);
|
||||
color: white;
|
||||
padding: 12px 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(245, 158, 11, 0.3);
|
||||
z-index: 1000;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.dev-warning .icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dev-warning .title {
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dev-warning .description {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<!-- 로딩 스켈레톤 UI -->
|
||||
<div id="react-kuntae-app" class="animate-fade-in">
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="space-y-6">
|
||||
{/* 경고 메시지 스켈레톤 */}
|
||||
<div class="bg-white/10 rounded-lg p-4 animate-pulse">
|
||||
<div class="h-6 bg-white/20 rounded w-3/4"></div>
|
||||
</div>
|
||||
|
||||
{/* 필터 스켈레톤 */}
|
||||
<div class="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="h-16 bg-white/10 rounded"></div>
|
||||
<div class="h-16 bg-white/10 rounded"></div>
|
||||
<div class="h-16 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 통계 카드 스켈레톤 */}
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div class="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div class="flex items-center">
|
||||
<div class="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div class="h-4 bg-white/20 rounded w-20 mb-2"></div>
|
||||
<div class="h-6 bg-white/20 rounded w-12"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div class="flex items-center">
|
||||
<div class="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div class="h-4 bg-white/20 rounded w-16 mb-2"></div>
|
||||
<div class="h-6 bg-white/20 rounded w-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div class="flex items-center">
|
||||
<div class="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div class="h-4 bg-white/20 rounded w-16 mb-2"></div>
|
||||
<div class="h-6 bg-white/20 rounded w-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="glass-effect rounded-lg p-6 animate-pulse">
|
||||
<div class="flex items-center">
|
||||
<div class="w-12 h-12 bg-white/20 rounded-lg mr-4"></div>
|
||||
<div>
|
||||
<div class="h-4 bg-white/20 rounded w-16 mb-2"></div>
|
||||
<div class="h-6 bg-white/20 rounded w-8"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 테이블 스켈레톤 */}
|
||||
<div class="glass-effect rounded-lg p-4 animate-pulse">
|
||||
<div class="space-y-3">
|
||||
<div class="grid grid-cols-7 gap-4">
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
<div class="h-6 bg-white/20 rounded"></div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="grid grid-cols-7 gap-4">
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
<div class="grid grid-cols-7 gap-4">
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
<div class="h-4 bg-white/10 rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React Local -->
|
||||
<script crossorigin src="/lib/js/react.development.js"></script>
|
||||
<script crossorigin src="/lib/js/react-dom.development.js"></script>
|
||||
<script src="/lib/js/babel.min.js"></script>
|
||||
|
||||
<!-- 공통 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/CommonNavigation"></script>
|
||||
<script type="text/babel" src="/react/component/DevWarning"></script>
|
||||
|
||||
<!-- 근태관리 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/Kuntae"></script>
|
||||
|
||||
<!-- 앱 컴포넌트 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<CommonNavigation currentPage="kuntae" />
|
||||
<Kuntae />
|
||||
<DevWarning />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 루트 렌더링
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-kuntae-app'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,177 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>로그인 - GroupWare (React)</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
},
|
||||
success: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
},
|
||||
warning: {
|
||||
50: '#fffbeb',
|
||||
100: '#fef3c7',
|
||||
200: '#fde68a',
|
||||
300: '#fcd34d',
|
||||
400: '#fbbf24',
|
||||
500: '#f59e0b',
|
||||
600: '#d97706',
|
||||
700: '#b45309',
|
||||
800: '#92400e',
|
||||
900: '#78350f',
|
||||
},
|
||||
danger: {
|
||||
50: '#fef2f2',
|
||||
100: '#fee2e2',
|
||||
200: '#fecaca',
|
||||
300: '#fca5a5',
|
||||
400: '#f87171',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
800: '#991b1b',
|
||||
900: '#7f1d1d',
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
'fade-in': 'fadeIn 0.6s ease-in-out',
|
||||
'slide-up': 'slideUp 0.4s ease-out',
|
||||
'bounce-in': 'bounceIn 0.6s ease-out',
|
||||
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
},
|
||||
keyframes: {
|
||||
fadeIn: {
|
||||
'0%': { opacity: '0' },
|
||||
'100%': { opacity: '1' },
|
||||
},
|
||||
slideUp: {
|
||||
'0%': { transform: 'translateY(20px)', opacity: '0' },
|
||||
'100%': { transform: 'translateY(0)', opacity: '1' },
|
||||
},
|
||||
bounceIn: {
|
||||
'0%': { transform: 'scale(0.3)', opacity: '0' },
|
||||
'50%': { transform: 'scale(1.05)' },
|
||||
'70%': { transform: 'scale(0.9)' },
|
||||
'100%': { transform: 'scale(1)', opacity: '1' },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.gradient-bg {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.input-focus {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.input-focus:focus {
|
||||
transform: scale(1.02);
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
.floating-label {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.input-field:focus + .floating-label,
|
||||
.input-field:not(:placeholder-shown) + .floating-label {
|
||||
transform: translateY(-1.5rem) scale(0.85);
|
||||
color: #3b82f6;
|
||||
}
|
||||
/* 드롭다운 스타일 */
|
||||
select.input-field option {
|
||||
background-color: #1f2937;
|
||||
color: white;
|
||||
}
|
||||
select.input-field:focus option:checked {
|
||||
background-color: #3b82f6;
|
||||
}
|
||||
select.input-field option:hover {
|
||||
background-color: #374151;
|
||||
}
|
||||
/* React 컴포넌트 전용 스타일 */
|
||||
.react-login-container {
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="react-login-app" class="react-login-container">
|
||||
<div class="gradient-bg min-h-screen flex items-center justify-center p-4">
|
||||
<div class="w-full max-w-md">
|
||||
<div class="glass-effect rounded-3xl p-8 card-hover">
|
||||
<div class="text-center">
|
||||
<div class="w-16 h-16 bg-white/20 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<svg class="w-8 h-8 text-white animate-pulse" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold text-white mb-2">GroupWare</h1>
|
||||
<p class="text-white/70 text-sm">React 로그인 컴포넌트를 로딩 중입니다...</p>
|
||||
<div class="mt-6">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-white mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React & ReactDOM CDN -->
|
||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
||||
<!-- Babel standalone for JSX -->
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
|
||||
<!-- React Login Component -->
|
||||
<script type="text/babel" src="/react/component/LoginApp"></script>
|
||||
|
||||
<!-- App Initialization -->
|
||||
<script type="text/babel">
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-login-app'));
|
||||
root.render(<LoginApp />);
|
||||
|
||||
console.log('✅ React 로그인 페이지가 성공적으로 마운트되었습니다.');
|
||||
console.log('📁 컴포넌트 파일: /react/LoginApp.jsx');
|
||||
console.log('🌐 페이지 URL: /react/login');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,191 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>프로젝트 관리 - GroupWare (React)</title>
|
||||
<link rel="stylesheet" href="/lib/css/tailwind.min.css">
|
||||
<script src="/lib/js/tailwind-config.js"></script>
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.animate-slide-up {
|
||||
animation: slideUp 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.bg-primary-500 {
|
||||
background-color: #3b82f6;
|
||||
}
|
||||
|
||||
.bg-primary-600 {
|
||||
background-color: #2563eb;
|
||||
}
|
||||
|
||||
.hover\:bg-primary-600:hover {
|
||||
background-color: #2563eb;
|
||||
}
|
||||
|
||||
.bg-green-500 {
|
||||
background-color: #10b981;
|
||||
}
|
||||
|
||||
.bg-green-600 {
|
||||
background-color: #059669;
|
||||
}
|
||||
|
||||
.hover\:bg-green-600:hover {
|
||||
background-color: #059669;
|
||||
}
|
||||
|
||||
.bg-red-500 {
|
||||
background-color: #ef4444;
|
||||
}
|
||||
|
||||
.bg-red-600 {
|
||||
background-color: #dc2626;
|
||||
}
|
||||
|
||||
.hover\:bg-red-600:hover {
|
||||
background-color: #dc2626;
|
||||
}
|
||||
|
||||
select option {
|
||||
background-color: #1f2937;
|
||||
color: white;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
select option:hover {
|
||||
background-color: #374151;
|
||||
}
|
||||
|
||||
select option:checked {
|
||||
background-color: #3b82f6;
|
||||
}
|
||||
|
||||
select option:focus {
|
||||
background-color: #374151;
|
||||
}
|
||||
|
||||
.loading {
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top: 3px solid #fff;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<div id="react-project">
|
||||
<!-- 스켈레톤 로딩 UI -->
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="glass-effect rounded-lg overflow-hidden animate-pulse">
|
||||
<div class="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<div class="h-6 bg-white/20 rounded w-40"></div>
|
||||
<div class="flex space-x-3">
|
||||
<div class="h-10 bg-white/20 rounded w-32"></div>
|
||||
<div class="h-10 bg-white/20 rounded w-24"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 p-4">
|
||||
<div class="bg-white/10 rounded-lg p-4">
|
||||
<div class="h-8 bg-white/20 rounded mb-2"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-16"></div>
|
||||
</div>
|
||||
<div class="bg-white/10 rounded-lg p-4">
|
||||
<div class="h-8 bg-white/20 rounded mb-2"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-16"></div>
|
||||
</div>
|
||||
<div class="bg-white/10 rounded-lg p-4">
|
||||
<div class="h-8 bg-white/20 rounded mb-2"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-16"></div>
|
||||
</div>
|
||||
<div class="bg-white/10 rounded-lg p-4">
|
||||
<div class="h-8 bg-white/20 rounded mb-2"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-16"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="space-y-4">
|
||||
<div class="h-4 bg-white/20 rounded w-full"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-3/4"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React Local -->
|
||||
<script crossorigin src="/lib/js/react.development.js"></script>
|
||||
<script crossorigin src="/lib/js/react-dom.development.js"></script>
|
||||
<script src="/lib/js/babel.min.js"></script>
|
||||
|
||||
<!-- 공통 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/CommonNavigation"></script>
|
||||
<script type="text/babel" src="/react/component/DevWarning"></script>
|
||||
|
||||
<!-- Project 컴포넌트 -->
|
||||
<script type="text/babel" src="/react/component/Project"></script>
|
||||
|
||||
<!-- 앱 초기화 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<CommonNavigation currentPage="project" />
|
||||
<Project />
|
||||
<DevWarning />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 루트 렌더링
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-project'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,197 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>React Test Page - GroupWare</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.status {
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.success {
|
||||
background-color: #d4edda;
|
||||
border: 1px solid #c3e6cb;
|
||||
color: #155724;
|
||||
}
|
||||
.loading {
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
color: #856404;
|
||||
}
|
||||
.error {
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
color: #721c24;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🚀 React Integration Test</h1>
|
||||
<p>GroupWare + OWIN + React 통합 테스트</p>
|
||||
</div>
|
||||
|
||||
<div id="react-app">
|
||||
<div class="status loading">
|
||||
React 컴포넌트를 로딩 중입니다...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React & ReactDOM CDN -->
|
||||
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
|
||||
<!-- Babel standalone for JSX -->
|
||||
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||
|
||||
<!-- React Component -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
// 메인 React 컴포넌트
|
||||
function ReactTestApp() {
|
||||
const [status, setStatus] = useState('loading');
|
||||
const [counter, setCounter] = useState(0);
|
||||
const [serverTime, setServerTime] = useState('');
|
||||
const [apiTest, setApiTest] = useState({ status: 'pending', message: '' });
|
||||
|
||||
// 컴포넌트가 마운트될 때 실행
|
||||
useEffect(() => {
|
||||
// React가 정상적으로 로드되었음을 표시
|
||||
setTimeout(() => {
|
||||
setStatus('success');
|
||||
setServerTime(new Date().toLocaleString('ko-KR'));
|
||||
}, 1000);
|
||||
|
||||
// API 테스트 (GroupWare의 기존 컨트롤러 테스트)
|
||||
testAPI();
|
||||
}, []);
|
||||
|
||||
// GroupWare API 테스트 함수
|
||||
const testAPI = async () => {
|
||||
try {
|
||||
// Home 컨트롤러 테스트 (기존에 있을 것으로 예상)
|
||||
const response = await fetch('/Home');
|
||||
if (response.ok) {
|
||||
setApiTest({ status: 'success', message: 'API 연결 성공' });
|
||||
} else {
|
||||
setApiTest({ status: 'warning', message: `API 응답: ${response.status}` });
|
||||
}
|
||||
} catch (error) {
|
||||
setApiTest({ status: 'error', message: `API 오류: ${error.message}` });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`status ${status === 'success' ? 'success' : 'loading'}`}>
|
||||
{status === 'success' ? (
|
||||
<div>
|
||||
<h3>✅ React 컴포넌트가 성공적으로 로드되었습니다!</h3>
|
||||
<p><strong>현재 시간:</strong> {serverTime}</p>
|
||||
</div>
|
||||
) : (
|
||||
<h3>React 컴포넌트를 로딩 중입니다...</h3>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{status === 'success' && (
|
||||
<div>
|
||||
<div className="status">
|
||||
<h3>📊 상태 관리 테스트</h3>
|
||||
<p><strong>카운터:</strong> {counter}</p>
|
||||
<button
|
||||
onClick={() => setCounter(counter + 1)}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
marginRight: '10px',
|
||||
backgroundColor: '#007bff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
증가 (+1)
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCounter(0)}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: '#6c757d',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
리셋
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={`status ${
|
||||
apiTest.status === 'success' ? 'success' :
|
||||
apiTest.status === 'error' ? 'error' : 'loading'
|
||||
}`}>
|
||||
<h3>🌐 API 연결 테스트</h3>
|
||||
<p><strong>상태:</strong> {apiTest.message}</p>
|
||||
<button
|
||||
onClick={testAPI}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: '#28a745',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
API 다시 테스트
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="status">
|
||||
<h3>📋 통합 테스트 체크리스트</h3>
|
||||
<ul style={{ textAlign: 'left' }}>
|
||||
<li>✅ OWIN 정적 파일 서빙</li>
|
||||
<li>✅ React 라이브러리 로딩 (CDN)</li>
|
||||
<li>✅ JSX 컴파일 (Babel)</li>
|
||||
<li>✅ React Hooks (useState, useEffect)</li>
|
||||
<li>✅ 이벤트 핸들링</li>
|
||||
<li>✅ API 호출 (fetch)</li>
|
||||
<li>✅ 반응형 UI 업데이트</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// React 컴포넌트를 DOM에 렌더링
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-app'));
|
||||
root.render(<ReactTestApp />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,115 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<meta name="version" content="v1.0-20250127">
|
||||
<title>할일 관리 - GroupWare (React)</title>
|
||||
<link rel="stylesheet" href="/lib/css/tailwind.min.css">
|
||||
<script src="/lib/js/tailwind-config.js"></script>
|
||||
<style>
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.gradient-bg {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
.card-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.loading {
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top: 3px solid #fff;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<div id="react-todo">
|
||||
<!-- 스켈레톤 로딩 UI -->
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="glass-effect rounded-2xl overflow-hidden animate-pulse">
|
||||
<div class="px-6 py-4 border-b border-white/10 flex items-center justify-between">
|
||||
<div class="h-6 bg-white/20 rounded w-40"></div>
|
||||
<div class="h-10 bg-white/20 rounded w-32"></div>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="space-y-4">
|
||||
<div class="h-4 bg-white/20 rounded w-full"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-3/4"></div>
|
||||
<div class="h-4 bg-white/20 rounded w-1/2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- React Local -->
|
||||
<script crossorigin src="/lib/js/react.development.js"></script>
|
||||
<script crossorigin src="/lib/js/react-dom.development.js"></script>
|
||||
<script src="/lib/js/babel.min.js"></script>
|
||||
|
||||
<!-- 공통 컴포넌트 로드 -->
|
||||
<script type="text/babel" src="/react/component/CommonNavigation"></script>
|
||||
<script type="text/babel" src="/react/component/DevWarning"></script>
|
||||
|
||||
<!-- Todo 컴포넌트 -->
|
||||
<script type="text/babel" src="/react/component/Todo"></script>
|
||||
|
||||
<!-- 앱 초기화 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<CommonNavigation currentPage="todo" />
|
||||
<Todo />
|
||||
<DevWarning />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 루트 렌더링
|
||||
const root = ReactDOM.createRoot(document.getElementById('react-todo'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1092,6 +1092,12 @@ namespace Project
|
||||
|
||||
private void 휴일연장근무집계표출력ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.otconfirm));
|
||||
//if(curLevel < 5)
|
||||
//{
|
||||
// Util.MsgE("이 기능을 사용할 권한이 없습니다");
|
||||
// return;
|
||||
//}
|
||||
var f = new FPJ0000.JobReport_.rJobReportOT();
|
||||
f.Show();
|
||||
}
|
||||
|
||||
Submodule Sub/tcpservice updated: 1680e266da...d7fe2baa0e
@@ -27,7 +27,7 @@ namespace FBS0000
|
||||
tbGrp.Text = string.Empty;
|
||||
//this.dv1.CellFormatting += dv1_CellFormatting;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void __Load(object sender, EventArgs e)
|
||||
{
|
||||
@@ -95,7 +95,7 @@ namespace FBS0000
|
||||
//var dtUser = JobReport.OrderBy(t => t.userProcess + t.name).GroupBy(t => t.id);// taUser.GetData(FCOMMON.info.Login.gcode, tbGrp.Text);
|
||||
|
||||
var dtUser = FCOMMON.DBM.getActiveUserTable(); //업무일지 미사용자로인해서 사용자 목록은 이것을 사용한다 220215
|
||||
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
var users = new List<userinfo>();
|
||||
var seq = 0;
|
||||
foreach (System.Data.DataRow dr in dtUser.Rows)
|
||||
@@ -126,9 +126,14 @@ namespace FBS0000
|
||||
if (dr["outdate"] == null) newuser.outdate = string.Empty;
|
||||
newuser.outdate = dr["outdate"].ToString();
|
||||
|
||||
if (curLevel >= 5 || newuser.empno == FCOMMON.info.Login.no)
|
||||
{
|
||||
users.Add(newuser);
|
||||
seq += 1;
|
||||
}
|
||||
|
||||
|
||||
users.Add(newuser);
|
||||
seq += 1;
|
||||
|
||||
}
|
||||
|
||||
//휴가테이블에서 데이터를 가져온다
|
||||
@@ -154,8 +159,8 @@ namespace FBS0000
|
||||
|
||||
}
|
||||
//이월잔액
|
||||
var jand = qta.WorkUserJan_Yesterday_Day(FCOMMON.info.Login.gcode, item.empno, sd.ToString("yyyy-01-01"), sd.AddDays(-1).ToShortDateString(), "999999","%");
|
||||
var jan = qta.WorkUserJan_Yesterday_Day(FCOMMON.info.Login.gcode, item.empno, sd.ToString("yyyy-01-01"), ed.ToShortDateString(), "999999","%");
|
||||
var jand = qta.WorkUserJan_Yesterday_Day(FCOMMON.info.Login.gcode, item.empno, sd.ToString("yyyy-01-01"), sd.AddDays(-1).ToShortDateString(), "999999", "%");
|
||||
var jan = qta.WorkUserJan_Yesterday_Day(FCOMMON.info.Login.gcode, item.empno, sd.ToString("yyyy-01-01"), ed.ToShortDateString(), "999999", "%");
|
||||
var used = 0.0;
|
||||
|
||||
fpSpread1_Sheet1.Rows[rowindex].ResetBorder();
|
||||
@@ -212,7 +217,7 @@ namespace FBS0000
|
||||
//현재인원값
|
||||
var bIndate = DateTime.TryParse(item.indate, out DateTime dtIn);
|
||||
var bOutdate = DateTime.TryParse(item.outdate, out DateTime dtOut);
|
||||
// Boolean usePerson = true;
|
||||
// Boolean usePerson = true;
|
||||
|
||||
//
|
||||
//if (bIndate == true && curDate.ToShortDateString().CompareTo(dtIn.ToShortDateString()) < 0)
|
||||
@@ -258,7 +263,7 @@ namespace FBS0000
|
||||
}
|
||||
|
||||
//근태 시작일자가 조회시작일보다 적다면, 데이터가 걸쳐진 것이므로 회색으로 처리하자 2308320
|
||||
if(dr.sdate.ToShortDateString().CompareTo(sd.ToShortDateString()) < 0)
|
||||
if (dr.sdate.ToShortDateString().CompareTo(sd.ToShortDateString()) < 0)
|
||||
{
|
||||
fpSpread1_Sheet1.Cells[rowindex, c].BackColor = Color.DimGray;
|
||||
fpSpread1_Sheet1.Cells[rowindex, c].ForeColor = Color.White;
|
||||
@@ -352,7 +357,7 @@ namespace FBS0000
|
||||
fpSpread1_Sheet1.Columns[c].Tag = ps;
|
||||
}
|
||||
|
||||
used = (float)jand-(float)jan ;
|
||||
used = (float)jand - (float)jan;
|
||||
//var jan = jand - used;
|
||||
fpSpread1_Sheet1.Cells[rowindex, c++].Value = jand != 0 ? jand.ToString() : string.Empty;
|
||||
fpSpread1_Sheet1.Cells[rowindex, c++].Value = used != 0 ? used.ToString() : string.Empty;
|
||||
|
||||
@@ -33,7 +33,8 @@ namespace FBS0000
|
||||
|
||||
this.tbMon.Text = DateTime.Now.ToShortDateString();
|
||||
cmbType.SelectedIndex = 0; //일기준으로한다
|
||||
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.holyday));
|
||||
if (curLevel < 5) cmbUser.Enabled = false;
|
||||
}
|
||||
|
||||
private void rJobReport_Load(object sender, EventArgs e)
|
||||
|
||||
@@ -78,8 +78,8 @@ namespace FBS0000
|
||||
var ed = DateTime.Parse(this.tbMon.Text);
|
||||
var sd = DateTime.Parse(ed.ToString("yyyy") + "-01-01");
|
||||
|
||||
//this.reportViewer1.LocalReport.DataSources.Clear();
|
||||
var uid = "%";// GetUIDValue();
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.holyday));
|
||||
var uid = curLevel > 5 ? "%" : FCOMMON.info.Login.no; // GetUIDValue();
|
||||
if (cmbType.SelectedIndex == 0)
|
||||
{
|
||||
taDay.Fill(this.dsReport.Holydata_Day, FCOMMON.info.Login.gcode, uid, sd.ToShortDateString(), ed.ToShortDateString());
|
||||
|
||||
@@ -79,14 +79,19 @@ namespace FBS0000
|
||||
복사ToolStripMenuItem.Enabled = true;
|
||||
toolStripButton2.Enabled = true;
|
||||
toolStripButton3.Enabled = true;
|
||||
}
|
||||
cmbUser.Enabled = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
toolStripButton3.Enabled = false;
|
||||
cmbUser.Enabled = false;
|
||||
toolStripButton3.Enabled = false;
|
||||
toolStripButton2.Enabled = false;
|
||||
btSave.Enabled = false;
|
||||
btDel.Enabled = false;
|
||||
btAdd.Enabled = false;
|
||||
toolStripLabel3.Enabled = false;
|
||||
|
||||
|
||||
RefreshData();
|
||||
//this.cmbUser.Enabled = false; //사용자를 고칠수 없게 한다.
|
||||
@@ -414,9 +419,13 @@ namespace FBS0000
|
||||
|
||||
private void toolStripButton5_Click(object sender, EventArgs e)
|
||||
{
|
||||
//var sd = DateTime.Now.ToString("yyyy-MM-01");
|
||||
//var ed = DateTime.Parse(DateTime.Now.AddMonths(1).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
|
||||
var f = new WorkTable();
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.holyday));
|
||||
if(curLevel < 5)
|
||||
{
|
||||
AR.UTIL.MsgE("사용 권한이 없습니다");
|
||||
return;
|
||||
}
|
||||
var f = new WorkTable();
|
||||
f.Show();
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ namespace FBS0000
|
||||
}
|
||||
else
|
||||
{
|
||||
cmbUser.Enabled = false;
|
||||
toolStripLabel3.Enabled = false;
|
||||
//toolStripButton3.Enabled = false;
|
||||
//toolStripButton2.Enabled = false;
|
||||
//btSave.Enabled = false;
|
||||
|
||||
@@ -44,11 +44,17 @@ namespace FBS0000
|
||||
this.dsReport.holydatasum.Clear();
|
||||
|
||||
var grp_user = dsReport.holydata.GroupBy(t => t.uid).ToList();
|
||||
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.holyday));
|
||||
|
||||
foreach (var grp in grp_user)
|
||||
{
|
||||
//cate group
|
||||
var first_user = grp.First();
|
||||
if (curLevel < 5 && grp.Key.Equals(FCOMMON.info.Login.no) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var grp_cate = grp.GroupBy(t => t.cate).ToList();
|
||||
foreach (var cate in grp_cate)
|
||||
{
|
||||
|
||||
379
SubProject/FPJ0000/DSKuntae.Designer.cs
generated
379
SubProject/FPJ0000/DSKuntae.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -20,32 +20,32 @@ WHERE (idx = @Original_idx)</CommandText>
|
||||
</DbCommand>
|
||||
</DeleteCommand>
|
||||
<InsertCommand>
|
||||
<DbCommand CommandType="Text" ModifiedByUser="true">
|
||||
<DbCommand CommandType="Text" ModifiedByUser="false">
|
||||
<CommandText>INSERT INTO EETGW_HolydayRequest
|
||||
(gcode, uid, cate, sdate, edate, conf, Remark, wuid, wdate, Response, HolyReason, HolyBackup, HolyLocation, HolyDays, HolyTimes, sendmail, stime, etime, conf_id, conf_time)
|
||||
VALUES (@gcode,@uid,@cate,@sdate,@edate,@conf,@Remark,@wuid,@wdate,@Response,@HolyReason,@HolyBackup,@HolyLocation,@HolyDays,@HolyTimes,@sendmail,@stime,@etime,@conf_id,@conf_time);
|
||||
SELECT idx, gcode, uid, cate, sdate, edate, conf, Remark, wuid, wdate FROM EETGW_HolydayRequest WHERE (idx = SCOPE_IDENTITY()) ORDER BY conf, sdate DESC</CommandText>
|
||||
<Parameters>
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="gcode" ColumnName="gcode" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@gcode" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="gcode" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="uid" ColumnName="uid" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@uid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="uid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="cate" ColumnName="cate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@cate" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="cate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sdate" ColumnName="sdate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@sdate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="edate" ColumnName="edate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@edate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="edate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf" ColumnName="conf" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@conf" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="conf" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Remark" ColumnName="Remark" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Remark" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Remark" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wuid" ColumnName="wuid" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@wuid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="wuid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wdate" ColumnName="wdate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@wdate" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="wdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Response" ColumnName="Response" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Response" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Response" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyReason" ColumnName="HolyReason" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyReason" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyReason" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyBackup" ColumnName="HolyBackup" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyBackup" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyBackup" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyLocation" ColumnName="HolyLocation" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyLocation" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyLocation" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyDays" ColumnName="HolyDays" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="int" DbType="Double" Direction="Input" ParameterName="@HolyDays" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyDays" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyTimes" ColumnName="HolyTimes" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="float" DbType="Double" Direction="Input" ParameterName="@HolyTimes" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyTimes" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sendmail" ColumnName="sendmail" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="bit" DbType="Boolean" Direction="Input" ParameterName="@sendmail" Precision="0" ProviderType="Bit" Scale="0" Size="1" SourceColumn="sendmail" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="stime" ColumnName="stime" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@stime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="stime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="etime" ColumnName="etime" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@etime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="etime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_id" ColumnName="conf_id" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@conf_id" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="conf_id" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_time" ColumnName="conf_time" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@conf_time" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="conf_time" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="gcode" ColumnName="gcode" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@gcode" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="gcode" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="uid" ColumnName="uid" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@uid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="uid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="cate" ColumnName="cate" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@cate" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="cate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sdate" ColumnName="sdate" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@sdate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="edate" ColumnName="edate" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@edate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="edate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf" ColumnName="conf" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@conf" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="conf" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Remark" ColumnName="Remark" DataSourceName="" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Remark" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Remark" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wuid" ColumnName="wuid" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@wuid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="wuid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wdate" ColumnName="wdate" DataSourceName="" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@wdate" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="wdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Response" ColumnName="Response" DataSourceName="" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Response" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Response" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyReason" ColumnName="HolyReason" DataSourceName="" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyReason" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyReason" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyBackup" ColumnName="HolyBackup" DataSourceName="" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyBackup" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyBackup" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyLocation" ColumnName="HolyLocation" DataSourceName="" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyLocation" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyLocation" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyDays" ColumnName="HolyDays" DataSourceName="" DataTypeServer="int" DbType="Double" Direction="Input" ParameterName="@HolyDays" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyDays" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyTimes" ColumnName="HolyTimes" DataSourceName="" DataTypeServer="float" DbType="Double" Direction="Input" ParameterName="@HolyTimes" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyTimes" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sendmail" ColumnName="sendmail" DataSourceName="" DataTypeServer="bit" DbType="Boolean" Direction="Input" ParameterName="@sendmail" Precision="0" ProviderType="Bit" Scale="0" Size="1" SourceColumn="sendmail" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="stime" ColumnName="stime" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@stime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="stime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="etime" ColumnName="etime" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@etime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="etime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_id" ColumnName="conf_id" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@conf_id" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="conf_id" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_time" ColumnName="conf_time" DataSourceName="" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@conf_time" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="conf_time" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
</Parameters>
|
||||
</DbCommand>
|
||||
</InsertCommand>
|
||||
@@ -58,17 +58,18 @@ SELECT idx, gcode, uid, cate, sdate, edate, conf, Remark, wuid, wdate FROM EETGW
|
||||
EETGW_HolydayRequest.etime, EETGW_HolydayRequest.conf_id, EETGW_HolydayRequest.conf_time
|
||||
FROM EETGW_HolydayRequest WITH (nolock) LEFT OUTER JOIN
|
||||
vGroupUser ON EETGW_HolydayRequest.uid = vGroupUser.id AND EETGW_HolydayRequest.gcode = vGroupUser.gcode
|
||||
WHERE (EETGW_HolydayRequest.gcode = @gcode) AND (EETGW_HolydayRequest.sdate >= @sd) AND (EETGW_HolydayRequest.sdate <= @ed)
|
||||
WHERE (EETGW_HolydayRequest.gcode = @gcode) AND (EETGW_HolydayRequest.sdate >= @sd) AND (EETGW_HolydayRequest.sdate <= @ed) AND (EETGW_HolydayRequest.uid LIKE @uid)
|
||||
ORDER BY EETGW_HolydayRequest.conf, EETGW_HolydayRequest.sdate DESC</CommandText>
|
||||
<Parameters>
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="gcode" ColumnName="gcode" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@gcode" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="gcode" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sd" ColumnName="sdate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@sd" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="ed" ColumnName="sdate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@ed" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="uid" ColumnName="uid" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@uid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="uid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
</Parameters>
|
||||
</DbCommand>
|
||||
</SelectCommand>
|
||||
<UpdateCommand>
|
||||
<DbCommand CommandType="Text" ModifiedByUser="true">
|
||||
<DbCommand CommandType="Text" ModifiedByUser="false">
|
||||
<CommandText>UPDATE EETGW_HolydayRequest
|
||||
SET gcode = @gcode, uid = @uid, cate = @cate, sdate = @sdate, edate = @edate, conf = @conf, Remark = @Remark, wuid = @wuid, wdate = @wdate, Response = @Response,
|
||||
HolyReason = @HolyReason, HolyBackup = @HolyBackup, HolyLocation = @HolyLocation, HolyDays = @HolyDays, HolyTimes = @HolyTimes, sendmail = @sendmail, stime = @stime,
|
||||
@@ -76,28 +77,28 @@ SET gcode = @gcode, uid = @uid, cate = @cate, sdate = @sdate, edate = @ed
|
||||
WHERE (idx = @Original_idx);
|
||||
SELECT idx, gcode, uid, cate, sdate, edate, conf, Remark, wuid, wdate FROM EETGW_HolydayRequest WHERE (idx = @idx) ORDER BY conf, sdate DESC</CommandText>
|
||||
<Parameters>
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="gcode" ColumnName="gcode" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@gcode" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="gcode" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="uid" ColumnName="uid" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@uid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="uid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="cate" ColumnName="cate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@cate" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="cate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sdate" ColumnName="sdate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@sdate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="edate" ColumnName="edate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@edate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="edate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf" ColumnName="conf" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@conf" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="conf" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Remark" ColumnName="Remark" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Remark" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Remark" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wuid" ColumnName="wuid" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@wuid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="wuid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wdate" ColumnName="wdate" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@wdate" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="wdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Response" ColumnName="Response" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Response" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Response" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyReason" ColumnName="HolyReason" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyReason" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyReason" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyBackup" ColumnName="HolyBackup" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyBackup" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyBackup" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyLocation" ColumnName="HolyLocation" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyLocation" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyLocation" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyDays" ColumnName="HolyDays" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="int" DbType="Double" Direction="Input" ParameterName="@HolyDays" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyDays" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyTimes" ColumnName="HolyTimes" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="float" DbType="Double" Direction="Input" ParameterName="@HolyTimes" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyTimes" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sendmail" ColumnName="sendmail" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="bit" DbType="Boolean" Direction="Input" ParameterName="@sendmail" Precision="0" ProviderType="Bit" Scale="0" Size="1" SourceColumn="sendmail" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="stime" ColumnName="stime" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@stime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="stime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="etime" ColumnName="etime" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@etime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="etime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_id" ColumnName="conf_id" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@conf_id" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="conf_id" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_time" ColumnName="conf_time" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@conf_time" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="conf_time" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="Original_idx" ColumnName="idx" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@Original_idx" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="idx" SourceColumnNullMapping="false" SourceVersion="Original" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="idx" ColumnName="idx" DataSourceName="EE.dbo.EETGW_HolydayRequest" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@idx" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="idx" SourceColumnNullMapping="false" SourceVersion="Original" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="gcode" ColumnName="gcode" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@gcode" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="gcode" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="uid" ColumnName="uid" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@uid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="uid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="cate" ColumnName="cate" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@cate" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="cate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sdate" ColumnName="sdate" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@sdate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="edate" ColumnName="edate" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@edate" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="edate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf" ColumnName="conf" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@conf" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="conf" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Remark" ColumnName="Remark" DataSourceName="" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Remark" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Remark" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wuid" ColumnName="wuid" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@wuid" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="wuid" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="wdate" ColumnName="wdate" DataSourceName="" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@wdate" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="wdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="Response" ColumnName="Response" DataSourceName="" DataTypeServer="varchar(255)" DbType="AnsiString" Direction="Input" ParameterName="@Response" Precision="0" ProviderType="VarChar" Scale="0" Size="255" SourceColumn="Response" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyReason" ColumnName="HolyReason" DataSourceName="" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyReason" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyReason" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyBackup" ColumnName="HolyBackup" DataSourceName="" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyBackup" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyBackup" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyLocation" ColumnName="HolyLocation" DataSourceName="" DataTypeServer="varchar(100)" DbType="AnsiString" Direction="Input" ParameterName="@HolyLocation" Precision="0" ProviderType="VarChar" Scale="0" Size="100" SourceColumn="HolyLocation" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyDays" ColumnName="HolyDays" DataSourceName="" DataTypeServer="int" DbType="Double" Direction="Input" ParameterName="@HolyDays" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyDays" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="HolyTimes" ColumnName="HolyTimes" DataSourceName="" DataTypeServer="float" DbType="Double" Direction="Input" ParameterName="@HolyTimes" Precision="0" ProviderType="Float" Scale="0" Size="8" SourceColumn="HolyTimes" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sendmail" ColumnName="sendmail" DataSourceName="" DataTypeServer="bit" DbType="Boolean" Direction="Input" ParameterName="@sendmail" Precision="0" ProviderType="Bit" Scale="0" Size="1" SourceColumn="sendmail" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="stime" ColumnName="stime" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@stime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="stime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="etime" ColumnName="etime" DataSourceName="" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@etime" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="etime" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_id" ColumnName="conf_id" DataSourceName="" DataTypeServer="varchar(20)" DbType="AnsiString" Direction="Input" ParameterName="@conf_id" Precision="0" ProviderType="VarChar" Scale="0" Size="20" SourceColumn="conf_id" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="conf_time" ColumnName="conf_time" DataSourceName="" DataTypeServer="smalldatetime" DbType="DateTime" Direction="Input" ParameterName="@conf_time" Precision="0" ProviderType="SmallDateTime" Scale="0" Size="4" SourceColumn="conf_time" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="Original_idx" ColumnName="idx" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@Original_idx" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="idx" SourceColumnNullMapping="false" SourceVersion="Original" />
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="idx" ColumnName="idx" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@idx" Precision="0" ProviderType="Int" Scale="0" Size="4" SourceColumn="idx" SourceColumnNullMapping="false" SourceVersion="Original" />
|
||||
</Parameters>
|
||||
</DbCommand>
|
||||
</UpdateCommand>
|
||||
@@ -138,152 +139,152 @@ SELECT idx, gcode, uid, cate, sdate, edate, conf, Remark, wuid, wdate FROM EETGW
|
||||
</DataSource>
|
||||
</xs:appinfo>
|
||||
</xs:annotation>
|
||||
<xs:element name="DSKuntae" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_UserDSName="DSKuntae" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="DSKuntae">
|
||||
<xs:element name="DSKuntae" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="DSKuntae" msprop:Generator_UserDSName="DSKuntae">
|
||||
<xs:complexType>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="EETGW_HolydayRequest" msprop:Generator_RowEvHandlerName="EETGW_HolydayRequestRowChangeEventHandler" msprop:Generator_RowDeletedName="EETGW_HolydayRequestRowDeleted" msprop:Generator_RowDeletingName="EETGW_HolydayRequestRowDeleting" msprop:Generator_RowEvArgName="EETGW_HolydayRequestRowChangeEvent" msprop:Generator_TablePropName="EETGW_HolydayRequest" msprop:Generator_RowChangedName="EETGW_HolydayRequestRowChanged" msprop:Generator_UserTableName="EETGW_HolydayRequest" msprop:Generator_RowChangingName="EETGW_HolydayRequestRowChanging" msprop:Generator_RowClassName="EETGW_HolydayRequestRow" msprop:Generator_TableClassName="EETGW_HolydayRequestDataTable" msprop:Generator_TableVarName="tableEETGW_HolydayRequest">
|
||||
<xs:element name="EETGW_HolydayRequest" msprop:Generator_UserTableName="EETGW_HolydayRequest" msprop:Generator_RowEvArgName="EETGW_HolydayRequestRowChangeEvent" msprop:Generator_TableVarName="tableEETGW_HolydayRequest" msprop:Generator_TablePropName="EETGW_HolydayRequest" msprop:Generator_RowDeletingName="EETGW_HolydayRequestRowDeleting" msprop:Generator_RowChangingName="EETGW_HolydayRequestRowChanging" msprop:Generator_RowDeletedName="EETGW_HolydayRequestRowDeleted" msprop:Generator_RowEvHandlerName="EETGW_HolydayRequestRowChangeEventHandler" msprop:Generator_TableClassName="EETGW_HolydayRequestDataTable" msprop:Generator_RowChangedName="EETGW_HolydayRequestRowChanged" msprop:Generator_RowClassName="EETGW_HolydayRequestRow">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="idx" msdata:ReadOnly="true" msdata:AutoIncrement="true" msdata:AutoIncrementSeed="-1" msdata:AutoIncrementStep="-1" msprop:Generator_ColumnPropNameInTable="idxColumn" msprop:Generator_ColumnPropNameInRow="idx" msprop:Generator_UserColumnName="idx" msprop:Generator_ColumnVarNameInTable="columnidx" type="xs:int" />
|
||||
<xs:element name="gcode" msprop:Generator_ColumnPropNameInTable="gcodeColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="gcode" msprop:Generator_UserColumnName="gcode" msprop:Generator_ColumnVarNameInTable="columngcode">
|
||||
<xs:element name="idx" msdata:ReadOnly="true" msdata:AutoIncrement="true" msdata:AutoIncrementSeed="-1" msdata:AutoIncrementStep="-1" msprop:Generator_ColumnVarNameInTable="columnidx" msprop:Generator_ColumnPropNameInRow="idx" msprop:Generator_ColumnPropNameInTable="idxColumn" msprop:Generator_UserColumnName="idx" type="xs:int" />
|
||||
<xs:element name="gcode" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="gcode" msprop:Generator_ColumnVarNameInTable="columngcode" msprop:Generator_ColumnPropNameInTable="gcodeColumn" msprop:Generator_UserColumnName="gcode">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="uid" msprop:Generator_ColumnPropNameInTable="uidColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="uid" msprop:Generator_UserColumnName="uid" msprop:Generator_ColumnVarNameInTable="columnuid" minOccurs="0">
|
||||
<xs:element name="uid" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="uid" msprop:Generator_ColumnVarNameInTable="columnuid" msprop:Generator_ColumnPropNameInTable="uidColumn" msprop:Generator_UserColumnName="uid" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="cate" msprop:Generator_ColumnPropNameInTable="cateColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="cate" msprop:Generator_UserColumnName="cate" msprop:Generator_ColumnVarNameInTable="columncate" minOccurs="0">
|
||||
<xs:element name="cate" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="cate" msprop:Generator_ColumnVarNameInTable="columncate" msprop:Generator_ColumnPropNameInTable="cateColumn" msprop:Generator_UserColumnName="cate" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="sdate" msprop:Generator_ColumnPropNameInTable="sdateColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="sdate" msprop:Generator_UserColumnName="sdate" msprop:Generator_ColumnVarNameInTable="columnsdate" minOccurs="0">
|
||||
<xs:element name="sdate" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="sdate" msprop:Generator_ColumnVarNameInTable="columnsdate" msprop:Generator_ColumnPropNameInTable="sdateColumn" msprop:Generator_UserColumnName="sdate" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="edate" msprop:Generator_ColumnPropNameInTable="edateColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="edate" msprop:Generator_UserColumnName="edate" msprop:Generator_ColumnVarNameInTable="columnedate" minOccurs="0">
|
||||
<xs:element name="edate" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="edate" msprop:Generator_ColumnVarNameInTable="columnedate" msprop:Generator_ColumnPropNameInTable="edateColumn" msprop:Generator_UserColumnName="edate" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Remark" msprop:Generator_ColumnPropNameInTable="RemarkColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="Remark" msprop:Generator_UserColumnName="Remark" msprop:Generator_ColumnVarNameInTable="columnRemark" minOccurs="0">
|
||||
<xs:element name="Remark" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="Remark" msprop:Generator_ColumnVarNameInTable="columnRemark" msprop:Generator_ColumnPropNameInTable="RemarkColumn" msprop:Generator_UserColumnName="Remark" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="wuid" msprop:Generator_ColumnPropNameInTable="wuidColumn" msprop:Generator_ColumnPropNameInRow="wuid" msprop:Generator_UserColumnName="wuid" msprop:Generator_ColumnVarNameInTable="columnwuid">
|
||||
<xs:element name="wuid" msprop:Generator_ColumnVarNameInTable="columnwuid" msprop:Generator_ColumnPropNameInRow="wuid" msprop:Generator_ColumnPropNameInTable="wuidColumn" msprop:Generator_UserColumnName="wuid">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="wdate" msprop:Generator_ColumnPropNameInTable="wdateColumn" msprop:Generator_ColumnPropNameInRow="wdate" msprop:Generator_UserColumnName="wdate" msprop:Generator_ColumnVarNameInTable="columnwdate" type="xs:dateTime" />
|
||||
<xs:element name="dept" msprop:Generator_ColumnPropNameInTable="deptColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="dept" msprop:Generator_UserColumnName="dept" msprop:Generator_ColumnVarNameInTable="columndept" minOccurs="0">
|
||||
<xs:element name="wdate" msprop:Generator_ColumnVarNameInTable="columnwdate" msprop:Generator_ColumnPropNameInRow="wdate" msprop:Generator_ColumnPropNameInTable="wdateColumn" msprop:Generator_UserColumnName="wdate" type="xs:dateTime" />
|
||||
<xs:element name="dept" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="dept" msprop:Generator_ColumnVarNameInTable="columndept" msprop:Generator_ColumnPropNameInTable="deptColumn" msprop:Generator_UserColumnName="dept" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="100" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="name" msprop:Generator_ColumnPropNameInTable="nameColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="name" msprop:Generator_UserColumnName="name" msprop:Generator_ColumnVarNameInTable="columnname" minOccurs="0">
|
||||
<xs:element name="name" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="name" msprop:Generator_ColumnVarNameInTable="columnname" msprop:Generator_ColumnPropNameInTable="nameColumn" msprop:Generator_UserColumnName="name" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="100" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="grade" msprop:Generator_ColumnPropNameInTable="gradeColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="grade" msprop:Generator_UserColumnName="grade" msprop:Generator_ColumnVarNameInTable="columngrade" minOccurs="0">
|
||||
<xs:element name="grade" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="grade" msprop:Generator_ColumnVarNameInTable="columngrade" msprop:Generator_ColumnPropNameInTable="gradeColumn" msprop:Generator_UserColumnName="grade" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="tel" msprop:Generator_ColumnPropNameInTable="telColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="tel" msprop:Generator_UserColumnName="tel" msprop:Generator_ColumnVarNameInTable="columntel" minOccurs="0">
|
||||
<xs:element name="tel" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="tel" msprop:Generator_ColumnVarNameInTable="columntel" msprop:Generator_ColumnPropNameInTable="telColumn" msprop:Generator_UserColumnName="tel" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="processs" msdata:ReadOnly="true" msprop:Generator_ColumnPropNameInTable="processsColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="processs" msprop:Generator_UserColumnName="processs" msprop:Generator_ColumnVarNameInTable="columnprocesss" minOccurs="0">
|
||||
<xs:element name="processs" msdata:ReadOnly="true" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="processs" msprop:Generator_ColumnVarNameInTable="columnprocesss" msprop:Generator_ColumnPropNameInTable="processsColumn" msprop:Generator_UserColumnName="processs" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="50" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Response" msprop:Generator_ColumnPropNameInTable="ResponseColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="Response" msprop:Generator_UserColumnName="Response" msprop:Generator_ColumnVarNameInTable="columnResponse" minOccurs="0">
|
||||
<xs:element name="Response" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="Response" msprop:Generator_ColumnVarNameInTable="columnResponse" msprop:Generator_ColumnPropNameInTable="ResponseColumn" msprop:Generator_UserColumnName="Response" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="conf" msprop:Generator_ColumnPropNameInTable="confColumn" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="conf" msprop:Generator_UserColumnName="conf" msprop:Generator_ColumnVarNameInTable="columnconf" type="xs:int" minOccurs="0" />
|
||||
<xs:element name="HolyReason" msprop:Generator_ColumnPropNameInTable="HolyReasonColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="HolyReason" msprop:Generator_UserColumnName="HolyReason" msprop:Generator_ColumnVarNameInTable="columnHolyReason" minOccurs="0">
|
||||
<xs:element name="conf" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="conf" msprop:Generator_ColumnVarNameInTable="columnconf" msprop:Generator_ColumnPropNameInTable="confColumn" msprop:Generator_UserColumnName="conf" type="xs:int" minOccurs="0" />
|
||||
<xs:element name="HolyReason" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="HolyReason" msprop:Generator_ColumnVarNameInTable="columnHolyReason" msprop:Generator_ColumnPropNameInTable="HolyReasonColumn" msprop:Generator_UserColumnName="HolyReason" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="100" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="HolyBackup" msprop:Generator_ColumnPropNameInTable="HolyBackupColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="HolyBackup" msprop:Generator_UserColumnName="HolyBackup" msprop:Generator_ColumnVarNameInTable="columnHolyBackup" minOccurs="0">
|
||||
<xs:element name="HolyBackup" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="HolyBackup" msprop:Generator_ColumnVarNameInTable="columnHolyBackup" msprop:Generator_ColumnPropNameInTable="HolyBackupColumn" msprop:Generator_UserColumnName="HolyBackup" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="100" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="HolyLocation" msprop:Generator_ColumnPropNameInTable="HolyLocationColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="HolyLocation" msprop:Generator_UserColumnName="HolyLocation" msprop:Generator_ColumnVarNameInTable="columnHolyLocation" minOccurs="0">
|
||||
<xs:element name="HolyLocation" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="HolyLocation" msprop:Generator_ColumnVarNameInTable="columnHolyLocation" msprop:Generator_ColumnPropNameInTable="HolyLocationColumn" msprop:Generator_UserColumnName="HolyLocation" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="100" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="HolyDays" msprop:Generator_ColumnPropNameInTable="HolyDaysColumn" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="HolyDays" msprop:Generator_UserColumnName="HolyDays" msprop:Generator_ColumnVarNameInTable="columnHolyDays" type="xs:double" minOccurs="0" />
|
||||
<xs:element name="HolyTimes" msprop:Generator_ColumnPropNameInTable="HolyTimesColumn" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="HolyTimes" msprop:Generator_UserColumnName="HolyTimes" msprop:Generator_ColumnVarNameInTable="columnHolyTimes" type="xs:double" minOccurs="0" />
|
||||
<xs:element name="sendmail" msprop:Generator_ColumnPropNameInTable="sendmailColumn" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="sendmail" msprop:Generator_UserColumnName="sendmail" msprop:Generator_ColumnVarNameInTable="columnsendmail" type="xs:boolean" minOccurs="0" />
|
||||
<xs:element name="stime" msprop:Generator_ColumnPropNameInTable="stimeColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="stime" msprop:Generator_UserColumnName="stime" msprop:Generator_ColumnVarNameInTable="columnstime" minOccurs="0">
|
||||
<xs:element name="HolyDays" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="HolyDays" msprop:Generator_ColumnVarNameInTable="columnHolyDays" msprop:Generator_ColumnPropNameInTable="HolyDaysColumn" msprop:Generator_UserColumnName="HolyDays" type="xs:double" minOccurs="0" />
|
||||
<xs:element name="HolyTimes" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="HolyTimes" msprop:Generator_ColumnVarNameInTable="columnHolyTimes" msprop:Generator_ColumnPropNameInTable="HolyTimesColumn" msprop:Generator_UserColumnName="HolyTimes" type="xs:double" minOccurs="0" />
|
||||
<xs:element name="sendmail" msprop:nullValue="0" msprop:Generator_ColumnPropNameInRow="sendmail" msprop:Generator_ColumnVarNameInTable="columnsendmail" msprop:Generator_ColumnPropNameInTable="sendmailColumn" msprop:Generator_UserColumnName="sendmail" type="xs:boolean" minOccurs="0" />
|
||||
<xs:element name="stime" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="stime" msprop:Generator_ColumnVarNameInTable="columnstime" msprop:Generator_ColumnPropNameInTable="stimeColumn" msprop:Generator_UserColumnName="stime" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="etime" msprop:Generator_ColumnPropNameInTable="etimeColumn" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="etime" msprop:Generator_UserColumnName="etime" msprop:Generator_ColumnVarNameInTable="columnetime" minOccurs="0">
|
||||
<xs:element name="etime" msprop:nullValue="_empty" msprop:Generator_ColumnPropNameInRow="etime" msprop:Generator_ColumnVarNameInTable="columnetime" msprop:Generator_ColumnPropNameInTable="etimeColumn" msprop:Generator_UserColumnName="etime" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="conf_id" msprop:Generator_ColumnPropNameInTable="conf_idColumn" msprop:Generator_ColumnPropNameInRow="conf_id" msprop:Generator_UserColumnName="conf_id" msprop:Generator_ColumnVarNameInTable="columnconf_id" minOccurs="0">
|
||||
<xs:element name="conf_id" msprop:Generator_ColumnVarNameInTable="columnconf_id" msprop:Generator_ColumnPropNameInRow="conf_id" msprop:Generator_ColumnPropNameInTable="conf_idColumn" msprop:Generator_UserColumnName="conf_id" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="conf_time" msprop:Generator_ColumnPropNameInTable="conf_timeColumn" msprop:Generator_ColumnPropNameInRow="conf_time" msprop:Generator_UserColumnName="conf_time" msprop:Generator_ColumnVarNameInTable="columnconf_time" type="xs:dateTime" minOccurs="0" />
|
||||
<xs:element name="conf_time" msprop:Generator_ColumnVarNameInTable="columnconf_time" msprop:Generator_ColumnPropNameInRow="conf_time" msprop:Generator_ColumnPropNameInTable="conf_timeColumn" msprop:Generator_UserColumnName="conf_time" type="xs:dateTime" minOccurs="0" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Changes to this file may cause incorrect behavior and will be lost if
|
||||
the code is regenerated.
|
||||
</autogenerated>-->
|
||||
<DiagramLayout xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ex:showrelationlabel="False" ViewPortX="385" ViewPortY="0" xmlns:ex="urn:schemas-microsoft-com:xml-msdatasource-layout-extended" xmlns="urn:schemas-microsoft-com:xml-msdatasource-layout">
|
||||
<DiagramLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ex:showrelationlabel="False" ViewPortX="385" ViewPortY="0" xmlns:ex="urn:schemas-microsoft-com:xml-msdatasource-layout-extended" xmlns="urn:schemas-microsoft-com:xml-msdatasource-layout">
|
||||
<Shapes>
|
||||
<Shape ID="DesignTable:EETGW_HolydayRequest" ZOrder="1" X="543" Y="76" Height="476" Width="287" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="425" />
|
||||
</Shapes>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
this.dte = new System.Windows.Forms.DateTimePicker();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.dts = new System.Windows.Forms.DateTimePicker();
|
||||
this.tbProcess = new System.Windows.Forms.ComboBox();
|
||||
this.cmbProcess = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.btRefresh = new System.Windows.Forms.Button();
|
||||
this.fpSpread1 = new FarPoint.Win.Spread.FpSpread();
|
||||
@@ -61,7 +61,7 @@
|
||||
this.panel1.Controls.Add(this.dte);
|
||||
this.panel1.Controls.Add(this.label2);
|
||||
this.panel1.Controls.Add(this.dts);
|
||||
this.panel1.Controls.Add(this.tbProcess);
|
||||
this.panel1.Controls.Add(this.cmbProcess);
|
||||
this.panel1.Controls.Add(this.label1);
|
||||
this.panel1.Controls.Add(this.btRefresh);
|
||||
this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
@@ -157,13 +157,13 @@
|
||||
//
|
||||
// tbProcess
|
||||
//
|
||||
this.tbProcess.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.tbProcess.FormattingEnabled = true;
|
||||
this.tbProcess.Location = new System.Drawing.Point(68, 32);
|
||||
this.tbProcess.Name = "tbProcess";
|
||||
this.tbProcess.Size = new System.Drawing.Size(180, 20);
|
||||
this.tbProcess.TabIndex = 5;
|
||||
this.tbProcess.SelectedIndexChanged += new System.EventHandler(this.tbProcess_SelectedIndexChanged);
|
||||
this.cmbProcess.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbProcess.FormattingEnabled = true;
|
||||
this.cmbProcess.Location = new System.Drawing.Point(68, 32);
|
||||
this.cmbProcess.Name = "tbProcess";
|
||||
this.cmbProcess.Size = new System.Drawing.Size(180, 20);
|
||||
this.cmbProcess.TabIndex = 5;
|
||||
this.cmbProcess.SelectedIndexChanged += new System.EventHandler(this.tbProcess_SelectedIndexChanged);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
@@ -239,7 +239,7 @@
|
||||
private System.Windows.Forms.DateTimePicker dte;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.DateTimePicker dts;
|
||||
private System.Windows.Forms.ComboBox tbProcess;
|
||||
private System.Windows.Forms.ComboBox cmbProcess;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Button btRefresh;
|
||||
private FarPoint.Win.Spread.FpSpread fpSpread1;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace FPJ0000.JobReport_
|
||||
public partial class fJobChartMenu : fBase
|
||||
{
|
||||
Boolean binit = false;
|
||||
|
||||
int curLevel = 0;// Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
public fJobChartMenu()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -22,7 +22,7 @@ namespace FPJ0000.JobReport_
|
||||
Properties.Settings.Default["gwcs"] = FCOMMON.info.CS;
|
||||
Properties.Settings.Default["EEEntities"] = FCOMMON.info.CS;
|
||||
Properties.Settings.Default["EEEntitiesLayout"] = FCOMMON.info.CS;
|
||||
|
||||
curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
|
||||
this.dts.Value = DateTime.Parse(DateTime.Now.AddMonths(-1).ToString("yyyy-MM-01"));
|
||||
this.dte.Value = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddDays(-1);
|
||||
@@ -30,19 +30,19 @@ namespace FPJ0000.JobReport_
|
||||
private void fJobChartMenu_Load(object sender, EventArgs e)
|
||||
{
|
||||
EnsureVisibleAndUsableSize();
|
||||
this.tbProcess.Items.Clear();
|
||||
this.cmbProcess.Items.Clear();
|
||||
|
||||
tbProcess.Items.Add("--전체--");
|
||||
cmbProcess.Items.Add("--전체--");
|
||||
// var taProcess = new dsReportTableAdapters.ProcessListTableAdapter();
|
||||
var dtProcessList = FCOMMON.DBM.GroupUserProcessList();// taProcess.GetData(FCOMMON.info.Login.gcode);
|
||||
foreach (var dr in dtProcessList)
|
||||
tbProcess.Items.Add(dr);
|
||||
cmbProcess.Items.Add(dr);
|
||||
|
||||
//사용자의 공정명을 선택해준다
|
||||
this.tbProcess.Text = FCOMMON.info.Login.process;
|
||||
this.cmbProcess.Text = FCOMMON.info.Login.process;
|
||||
|
||||
//프로세스가 선택되지 않았다면 전체를 선택해준다.
|
||||
if (tbProcess.SelectedIndex < 0) tbProcess.SelectedIndex = 0;
|
||||
if (cmbProcess.SelectedIndex < 0) cmbProcess.SelectedIndex = 0;
|
||||
|
||||
//사용자 목록을 선택한다
|
||||
UpdateUserList();
|
||||
@@ -59,6 +59,12 @@ namespace FPJ0000.JobReport_
|
||||
binit = true;
|
||||
btSave.Enabled = true;
|
||||
btRefresh.Enabled = true;
|
||||
|
||||
if(curLevel < 5)
|
||||
{
|
||||
this.cmbProcess.Enabled = false;
|
||||
cmbUser.Enabled = false;
|
||||
}
|
||||
}
|
||||
void UpdateUserList()
|
||||
{
|
||||
@@ -80,7 +86,7 @@ namespace FPJ0000.JobReport_
|
||||
var id = item.Field<string>("id");
|
||||
var dispname = item.Field<string>("dispname");
|
||||
var process = item.Field<string>("process");
|
||||
if (tbProcess.SelectedIndex > 0 && tbProcess.Text.Equals(process) == false) continue;
|
||||
if (cmbProcess.SelectedIndex > 0 && cmbProcess.Text.Equals(process) == false) continue;
|
||||
cmbUser.Items.Add(dispname);
|
||||
}
|
||||
|
||||
@@ -96,7 +102,7 @@ namespace FPJ0000.JobReport_
|
||||
////if (tbProcess.SelectedIndex != 0) userlist = userlist.Where(t => t.processs == tbProcess.Text); //해당 공정의 인원만 처리한다
|
||||
|
||||
|
||||
if (tbProcess.SelectedIndex > 0)
|
||||
if (cmbProcess.SelectedIndex > 0)
|
||||
cmbUser.Text = string.Format("{1}({0})", FCOMMON.info.Login.no, FCOMMON.info.Login.nameK);
|
||||
|
||||
if (cmbUser.SelectedIndex < 0) cmbUser.SelectedIndex = 0; //기본전체로 선택해준다.
|
||||
@@ -120,7 +126,7 @@ namespace FPJ0000.JobReport_
|
||||
fpSpread1.Visible = false;
|
||||
|
||||
//조회공정
|
||||
this.fpSpread1.Sheets[0].Cells[3, 2].Value = tbProcess.Text;
|
||||
this.fpSpread1.Sheets[0].Cells[3, 2].Value = cmbProcess.Text;
|
||||
|
||||
//담당자
|
||||
this.fpSpread1.Sheets[0].Cells[3, 3].Value = cmbUser.Text;
|
||||
@@ -159,9 +165,9 @@ namespace FPJ0000.JobReport_
|
||||
var UserNo = getUserID();// cmbUser.Text.Substring(1, cmbUser.Text.IndexOf(']') - 1);
|
||||
userCount = 1;// db.vJobReportForUser.Where(t => t.gcode == FCOMMON.info.Login.gcode && t.id == UserNo).GroupBy(t=>t.id).Count();
|
||||
}
|
||||
else if (tbProcess.SelectedIndex > 0)
|
||||
else if (cmbProcess.SelectedIndex > 0)
|
||||
{
|
||||
userCount = (int)taJobreportuser.GetProcessUserCount(FCOMMON.info.Login.gcode,tbProcess.Text);// db.vJobReportForUser.Where(t => t.gcode == FCOMMON.info.Login.gcode && t.userProcess == tbProcess.Text).GroupBy(t => t.id).Count();
|
||||
userCount = (int)taJobreportuser.GetProcessUserCount(FCOMMON.info.Login.gcode,cmbProcess.Text);// db.vJobReportForUser.Where(t => t.gcode == FCOMMON.info.Login.gcode && t.userProcess == tbProcess.Text).GroupBy(t => t.id).Count();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -188,9 +194,9 @@ namespace FPJ0000.JobReport_
|
||||
//.OrderBy(t => t.pdate)
|
||||
//.ToList();
|
||||
}
|
||||
else if (tbProcess.SelectedIndex > 0)
|
||||
else if (cmbProcess.SelectedIndex > 0)
|
||||
{
|
||||
baseData = taJobreportuser.GetByProcess(FCOMMON.info.Login.gcode, tbProcess.Text, vSD, vED);// db.vJobReportForUser
|
||||
baseData = taJobreportuser.GetByProcess(FCOMMON.info.Login.gcode, cmbProcess.Text, vSD, vED);// db.vJobReportForUser
|
||||
//.Where(t => t.gcode == FCOMMON.info.Login.gcode && t.pdate.CompareTo(vSD) >= 0 && t.pdate.CompareTo(vED) <= 0 && t.userProcess == tbProcess.Text)
|
||||
//.OrderBy(t => t.name)
|
||||
//.OrderBy(t => t.pdate)
|
||||
|
||||
429
SubProject/FPJ0000/JobReport_/fJobReport.Designer.cs
generated
429
SubProject/FPJ0000/JobReport_/fJobReport.Designer.cs
generated
@@ -30,27 +30,27 @@
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fJobReport));
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType1 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType2 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType3 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType4 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType5 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType6 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType7 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType8 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType9 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType10 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType1 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType2 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType3 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType11 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.DateTimeCellType dateTimeCellType1 = new FarPoint.Win.Spread.CellType.DateTimeCellType();
|
||||
FarPoint.Win.Spread.CellType.DateTimeCellType dateTimeCellType2 = new FarPoint.Win.Spread.CellType.DateTimeCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType12 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType13 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType4 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType14 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType5 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType15 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType16 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType17 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType18 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType19 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType20 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType21 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType22 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType23 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType24 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType6 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType7 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType8 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType25 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.DateTimeCellType dateTimeCellType3 = new FarPoint.Win.Spread.CellType.DateTimeCellType();
|
||||
FarPoint.Win.Spread.CellType.DateTimeCellType dateTimeCellType4 = new FarPoint.Win.Spread.CellType.DateTimeCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType26 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType27 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType9 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
FarPoint.Win.Spread.CellType.TextCellType textCellType28 = new FarPoint.Win.Spread.CellType.TextCellType();
|
||||
FarPoint.Win.Spread.CellType.NumberCellType numberCellType10 = new FarPoint.Win.Spread.CellType.NumberCellType();
|
||||
this.bn = new System.Windows.Forms.BindingNavigator(this.components);
|
||||
this.bs = new System.Windows.Forms.BindingSource(this.components);
|
||||
this.dsMSSQL = new FPJ0000.dsPRJ();
|
||||
@@ -105,7 +105,6 @@
|
||||
this.tam = new FPJ0000.dsPRJTableAdapters.TableAdapterManager();
|
||||
this.ta = new FPJ0000.dsPRJTableAdapters.JobReportTableAdapter();
|
||||
this.fpSpread1 = new FarPoint.Win.Spread.FpSpread();
|
||||
this.fpSpread1_Sheet1 = new FarPoint.Win.Spread.SheetView();
|
||||
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
||||
this.toolStripButton8 = new System.Windows.Forms.ToolStripButton();
|
||||
this.lbStt = new System.Windows.Forms.ToolStripLabel();
|
||||
@@ -128,18 +127,19 @@
|
||||
this.toolStripButton6 = new System.Windows.Forms.ToolStripButton();
|
||||
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
|
||||
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
|
||||
this.fpSpread1_Sheet1 = new FarPoint.Win.Spread.SheetView();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bn)).BeginInit();
|
||||
this.bn.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bs)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.dsMSSQL)).BeginInit();
|
||||
this.cm.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.fpSpread1)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.fpSpread1_Sheet1)).BeginInit();
|
||||
this.toolStrip1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
|
||||
this.splitContainer1.Panel1.SuspendLayout();
|
||||
this.splitContainer1.Panel2.SuspendLayout();
|
||||
this.splitContainer1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.fpSpread1_Sheet1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// bn
|
||||
@@ -228,7 +228,6 @@
|
||||
//
|
||||
this.bindingNavigatorPositionItem.AccessibleName = "위치";
|
||||
this.bindingNavigatorPositionItem.AutoSize = false;
|
||||
this.bindingNavigatorPositionItem.Font = new System.Drawing.Font("맑은 고딕", 9F);
|
||||
this.bindingNavigatorPositionItem.Name = "bindingNavigatorPositionItem";
|
||||
this.bindingNavigatorPositionItem.Size = new System.Drawing.Size(50, 23);
|
||||
this.bindingNavigatorPositionItem.Text = "0";
|
||||
@@ -320,7 +319,6 @@
|
||||
// tbFind
|
||||
//
|
||||
this.tbFind.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.tbFind.Font = new System.Drawing.Font("맑은 고딕", 9F);
|
||||
this.tbFind.Name = "tbFind";
|
||||
this.tbFind.Size = new System.Drawing.Size(100, 25);
|
||||
this.tbFind.KeyDown += new System.Windows.Forms.KeyEventHandler(this.tbFind_KeyDown);
|
||||
@@ -642,193 +640,7 @@
|
||||
this.fpSpread1.Size = new System.Drawing.Size(1364, 592);
|
||||
this.fpSpread1.StatusBarVisible = true;
|
||||
this.fpSpread1.TabIndex = 2;
|
||||
//
|
||||
// fpSpread1_Sheet1
|
||||
//
|
||||
this.fpSpread1_Sheet1.Reset();
|
||||
this.fpSpread1_Sheet1.SheetName = "Sheet1";
|
||||
// Formulas and custom names must be loaded with R1C1 reference style
|
||||
this.fpSpread1_Sheet1.ReferenceStyle = FarPoint.Win.Spread.Model.ReferenceStyle.R1C1;
|
||||
this.fpSpread1_Sheet1.ColumnCount = 21;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.RowCount = 2;
|
||||
this.fpSpread1_Sheet1.ActiveColumnIndex = -1;
|
||||
this.fpSpread1_Sheet1.ActiveRowIndex = -1;
|
||||
this.fpSpread1_Sheet1.AutoGenerateColumns = false;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 0).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 0).Value = "날짜";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 1).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 1).Value = "WW";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 2).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 2).Value = "담당";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 3).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 3).Value = "요청부서";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 4).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 4).Value = "패키지";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 5).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 5).Value = "상태";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 6).ColumnSpan = 3;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 6).Value = "업무형태";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 7).Value = "(공정)업무분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 8).Value = "업무분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 9).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 9).Value = "프로젝트(아이템)";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 10).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 10).Value = "*";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 11).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 11).Value = "시간";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 12).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 12).Value = "초과";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 13).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 13).Value = "비고";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 14).ColumnSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 14).Value = "초과시간범위";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 15).Value = "초과종료";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 16).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 16).Value = "기술분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 17).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 17).Value = "기술레벨";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 18).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 18).Value = "기술료($K)";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 19).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 19).Value = "#";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 20).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 20).Value = "일련번호";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 6).Value = "형태";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 7).Value = "분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 8).Value = "공정";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 14).Value = "시작";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 15).Value = "종료";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Rows.Get(0).Height = 30F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(0).CellType = textCellType1;
|
||||
this.fpSpread1_Sheet1.Columns.Get(0).DataField = "pdate";
|
||||
this.fpSpread1_Sheet1.Columns.Get(0).Width = 58F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).CellType = textCellType2;
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).DataField = "ww";
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).CellType = textCellType3;
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).DataField = "username";
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).CellType = textCellType4;
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).DataField = "requestpart";
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).Width = 78F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).CellType = textCellType5;
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).DataField = "package";
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).Width = 86F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(5).CellType = textCellType6;
|
||||
this.fpSpread1_Sheet1.Columns.Get(5).DataField = "status";
|
||||
this.fpSpread1_Sheet1.Columns.Get(5).Tag = "status";
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).CellType = textCellType7;
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).DataField = "type";
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).Label = "형태";
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).Width = 84F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).CellType = textCellType8;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).DataField = "jobgrp";
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).Label = "분류";
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).Width = 90F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).CellType = textCellType9;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).DataField = "process";
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Left;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).Label = "공정";
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).Width = 80F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).CellType = textCellType10;
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).DataField = "projectName";
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).Width = 158F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
numberCellType1.DecimalPlaces = 0;
|
||||
numberCellType1.LeadingZero = FarPoint.Win.Spread.CellType.LeadingZero.Yes;
|
||||
numberCellType1.MaximumValue = 2147483647D;
|
||||
numberCellType1.MinimumValue = -2147483648D;
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).CellType = numberCellType1;
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).DataField = "pidx";
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).Tag = "pidx";
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).Width = 39F;
|
||||
numberCellType2.MaximumValue = 999999999999999D;
|
||||
numberCellType2.MinimumValue = -999999999999999D;
|
||||
this.fpSpread1_Sheet1.Columns.Get(11).CellType = numberCellType2;
|
||||
this.fpSpread1_Sheet1.Columns.Get(11).DataField = "hrs";
|
||||
this.fpSpread1_Sheet1.Columns.Get(11).Width = 52F;
|
||||
numberCellType3.MaximumValue = 999999999999999D;
|
||||
numberCellType3.MinimumValue = -999999999999999D;
|
||||
numberCellType3.NullDisplay = "--";
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).CellType = numberCellType3;
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).DataField = "ot";
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).ForeColor = System.Drawing.Color.Red;
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).CellType = textCellType11;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).DataField = "description";
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Left;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).Width = 113F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(224)))), ((int)(((byte)(192)))));
|
||||
dateTimeCellType1.Calendar = new System.Globalization.GregorianCalendar(System.Globalization.GregorianCalendarTypes.Localized);
|
||||
dateTimeCellType1.CalendarSurroundingDaysColor = System.Drawing.SystemColors.GrayText;
|
||||
dateTimeCellType1.DateTimeFormat = FarPoint.Win.Spread.CellType.DateTimeFormat.TimeOnly;
|
||||
dateTimeCellType1.MaximumTime = System.TimeSpan.Parse("23:59:59.9999999");
|
||||
dateTimeCellType1.TimeDefault = new System.DateTime(2025, 8, 28, 22, 53, 4, 0);
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).CellType = dateTimeCellType1;
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).DataField = "otStart";
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).Label = "시작";
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(224)))), ((int)(((byte)(192)))));
|
||||
dateTimeCellType2.Calendar = new System.Globalization.GregorianCalendar(System.Globalization.GregorianCalendarTypes.Localized);
|
||||
dateTimeCellType2.CalendarSurroundingDaysColor = System.Drawing.SystemColors.GrayText;
|
||||
dateTimeCellType2.DateTimeFormat = FarPoint.Win.Spread.CellType.DateTimeFormat.TimeOnly;
|
||||
dateTimeCellType2.MaximumTime = System.TimeSpan.Parse("23:59:59.9999999");
|
||||
dateTimeCellType2.TimeDefault = new System.DateTime(2025, 8, 28, 22, 53, 4, 0);
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).CellType = dateTimeCellType2;
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).DataField = "otEnd";
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).Label = "종료";
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).CellType = textCellType12;
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).DataField = "kisuldiv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).Tag = "kisuldiv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).CellType = textCellType13;
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).DataField = "kisullv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).Tag = "kisullv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
numberCellType4.DecimalPlaces = 2;
|
||||
numberCellType4.NegativeRed = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).CellType = numberCellType4;
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).DataField = "kisulamt";
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).Tag = "kisulamt";
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(19).CellType = textCellType14;
|
||||
this.fpSpread1_Sheet1.Columns.Get(19).DataField = "tag";
|
||||
this.fpSpread1_Sheet1.Columns.Get(19).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
numberCellType5.DecimalPlaces = 0;
|
||||
numberCellType5.MaximumValue = 10000000D;
|
||||
numberCellType5.MinimumValue = -10000000D;
|
||||
this.fpSpread1_Sheet1.Columns.Get(20).CellType = numberCellType5;
|
||||
this.fpSpread1_Sheet1.Columns.Get(20).DataField = "idx";
|
||||
this.fpSpread1_Sheet1.Columns.Get(20).Tag = "idx";
|
||||
this.fpSpread1_Sheet1.DataAutoCellTypes = false;
|
||||
this.fpSpread1_Sheet1.DataAutoSizeColumns = false;
|
||||
this.fpSpread1_Sheet1.DataSource = this.bs;
|
||||
this.fpSpread1_Sheet1.Protect = false;
|
||||
this.fpSpread1_Sheet1.RowHeader.Columns.Default.Resizable = false;
|
||||
this.fpSpread1_Sheet1.SelectionPolicy = FarPoint.Win.Spread.Model.SelectionPolicy.MultiRange;
|
||||
this.fpSpread1_Sheet1.ShowEditingRowSelector = true;
|
||||
this.fpSpread1_Sheet1.ShowRowSelector = true;
|
||||
this.fpSpread1_Sheet1.ReferenceStyle = FarPoint.Win.Spread.Model.ReferenceStyle.A1;
|
||||
this.fpSpread1.CellClick += new FarPoint.Win.Spread.CellClickEventHandler(this.fpSpread1_CellClick);
|
||||
//
|
||||
// toolStrip1
|
||||
//
|
||||
@@ -880,7 +692,6 @@
|
||||
// dtSD
|
||||
//
|
||||
this.dtSD.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.dtSD.Font = new System.Drawing.Font("맑은 고딕", 9F);
|
||||
this.dtSD.Name = "dtSD";
|
||||
this.dtSD.Size = new System.Drawing.Size(90, 37);
|
||||
this.dtSD.Text = "1982-11-23";
|
||||
@@ -904,7 +715,6 @@
|
||||
// dtED
|
||||
//
|
||||
this.dtED.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.dtED.Font = new System.Drawing.Font("맑은 고딕", 9F);
|
||||
this.dtED.Name = "dtED";
|
||||
this.dtED.Size = new System.Drawing.Size(90, 37);
|
||||
this.dtED.Text = "1982-11-23";
|
||||
@@ -940,7 +750,6 @@
|
||||
// tbProcess
|
||||
//
|
||||
this.tbProcess.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))));
|
||||
this.tbProcess.Font = new System.Drawing.Font("맑은 고딕", 9F);
|
||||
this.tbProcess.Name = "tbProcess";
|
||||
this.tbProcess.Size = new System.Drawing.Size(200, 37);
|
||||
//
|
||||
@@ -1043,6 +852,194 @@
|
||||
this.splitContainer1.SplitterWidth = 10;
|
||||
this.splitContainer1.TabIndex = 6;
|
||||
//
|
||||
// fpSpread1_Sheet1
|
||||
//
|
||||
this.fpSpread1_Sheet1.Reset();
|
||||
this.fpSpread1_Sheet1.SheetName = "Sheet1";
|
||||
// Formulas and custom names must be loaded with R1C1 reference style
|
||||
this.fpSpread1_Sheet1.ReferenceStyle = FarPoint.Win.Spread.Model.ReferenceStyle.R1C1;
|
||||
this.fpSpread1_Sheet1.ColumnCount = 21;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.RowCount = 2;
|
||||
this.fpSpread1_Sheet1.ActiveColumnIndex = -1;
|
||||
this.fpSpread1_Sheet1.ActiveRowIndex = -1;
|
||||
this.fpSpread1_Sheet1.AutoGenerateColumns = false;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 0).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 0).Value = "날짜";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 1).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 1).Value = "WW";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 2).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 2).Value = "담당";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 3).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 3).Value = "요청부서";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 4).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 4).Value = "패키지";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 5).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 5).Value = "상태";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 6).ColumnSpan = 3;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 6).Value = "업무형태";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 7).Value = "(공정)업무분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 8).Value = "업무분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 9).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 9).Value = "프로젝트(아이템)";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 10).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 10).Value = "*";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 11).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 11).Value = "시간";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 12).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 12).Value = "초과";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 13).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 13).Value = "비고";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 14).ColumnSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 14).Value = "초과시간범위";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 15).Value = "초과종료";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 16).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 16).Value = "기술분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 17).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 17).Value = "기술레벨";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 18).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 18).Value = "기술료($K)";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 19).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 19).Value = "#";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 20).RowSpan = 2;
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(0, 20).Value = "일련번호";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 6).Value = "형태";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 7).Value = "분류";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 8).Value = "공정";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 14).Value = "시작";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Cells.Get(1, 15).Value = "종료";
|
||||
this.fpSpread1_Sheet1.ColumnHeader.Rows.Get(0).Height = 30F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(0).CellType = textCellType15;
|
||||
this.fpSpread1_Sheet1.Columns.Get(0).DataField = "pdate";
|
||||
this.fpSpread1_Sheet1.Columns.Get(0).Width = 58F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).CellType = textCellType16;
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).DataField = "ww";
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(1).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).CellType = textCellType17;
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).DataField = "username";
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(2).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).CellType = textCellType18;
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).DataField = "requestpart";
|
||||
this.fpSpread1_Sheet1.Columns.Get(3).Width = 78F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).CellType = textCellType19;
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).DataField = "package";
|
||||
this.fpSpread1_Sheet1.Columns.Get(4).Width = 86F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(5).CellType = textCellType20;
|
||||
this.fpSpread1_Sheet1.Columns.Get(5).DataField = "status";
|
||||
this.fpSpread1_Sheet1.Columns.Get(5).Tag = "status";
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).CellType = textCellType21;
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).DataField = "type";
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).Label = "형태";
|
||||
this.fpSpread1_Sheet1.Columns.Get(6).Width = 84F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).CellType = textCellType22;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).DataField = "jobgrp";
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).Label = "분류";
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(7).Width = 90F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).CellType = textCellType23;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).DataField = "process";
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Left;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).Label = "공정";
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(8).Width = 80F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).AllowAutoFilter = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).CellType = textCellType24;
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).DataField = "projectName";
|
||||
this.fpSpread1_Sheet1.Columns.Get(9).Width = 158F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
numberCellType6.DecimalPlaces = 0;
|
||||
numberCellType6.LeadingZero = FarPoint.Win.Spread.CellType.LeadingZero.Yes;
|
||||
numberCellType6.MaximumValue = 2147483647D;
|
||||
numberCellType6.MinimumValue = -2147483648D;
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).CellType = numberCellType6;
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).DataField = "pidx";
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).Tag = "pidx";
|
||||
this.fpSpread1_Sheet1.Columns.Get(10).Width = 39F;
|
||||
numberCellType7.MaximumValue = 999999999999999D;
|
||||
numberCellType7.MinimumValue = -999999999999999D;
|
||||
this.fpSpread1_Sheet1.Columns.Get(11).CellType = numberCellType7;
|
||||
this.fpSpread1_Sheet1.Columns.Get(11).DataField = "hrs";
|
||||
this.fpSpread1_Sheet1.Columns.Get(11).Width = 52F;
|
||||
numberCellType8.MaximumValue = 999999999999999D;
|
||||
numberCellType8.MinimumValue = -999999999999999D;
|
||||
numberCellType8.NullDisplay = "--";
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).CellType = numberCellType8;
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).DataField = "ot";
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).ForeColor = System.Drawing.Color.Red;
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).Tag = "ot";
|
||||
this.fpSpread1_Sheet1.Columns.Get(12).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).CellType = textCellType25;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).DataField = "description";
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Left;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(13).Width = 113F;
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(224)))), ((int)(((byte)(192)))));
|
||||
dateTimeCellType3.Calendar = new System.Globalization.GregorianCalendar(System.Globalization.GregorianCalendarTypes.Localized);
|
||||
dateTimeCellType3.CalendarSurroundingDaysColor = System.Drawing.SystemColors.GrayText;
|
||||
dateTimeCellType3.DateTimeFormat = FarPoint.Win.Spread.CellType.DateTimeFormat.TimeOnly;
|
||||
dateTimeCellType3.MaximumTime = System.TimeSpan.Parse("23:59:59.9999999");
|
||||
dateTimeCellType3.TimeDefault = new System.DateTime(2025, 11, 11, 22, 53, 4, 0);
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).CellType = dateTimeCellType3;
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).DataField = "otStart";
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).Label = "시작";
|
||||
this.fpSpread1_Sheet1.Columns.Get(14).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(224)))), ((int)(((byte)(192)))));
|
||||
dateTimeCellType4.Calendar = new System.Globalization.GregorianCalendar(System.Globalization.GregorianCalendarTypes.Localized);
|
||||
dateTimeCellType4.CalendarSurroundingDaysColor = System.Drawing.SystemColors.GrayText;
|
||||
dateTimeCellType4.DateTimeFormat = FarPoint.Win.Spread.CellType.DateTimeFormat.TimeOnly;
|
||||
dateTimeCellType4.MaximumTime = System.TimeSpan.Parse("23:59:59.9999999");
|
||||
dateTimeCellType4.TimeDefault = new System.DateTime(2025, 11, 11, 22, 53, 4, 0);
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).CellType = dateTimeCellType4;
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).DataField = "otEnd";
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).Label = "종료";
|
||||
this.fpSpread1_Sheet1.Columns.Get(15).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).CellType = textCellType26;
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).DataField = "kisuldiv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).Tag = "kisuldiv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(16).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).CellType = textCellType27;
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).DataField = "kisullv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).Tag = "kisullv";
|
||||
this.fpSpread1_Sheet1.Columns.Get(17).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
numberCellType9.DecimalPlaces = 2;
|
||||
numberCellType9.NegativeRed = true;
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).CellType = numberCellType9;
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).DataField = "kisulamt";
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).HorizontalAlignment = FarPoint.Win.Spread.CellHorizontalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).Tag = "kisulamt";
|
||||
this.fpSpread1_Sheet1.Columns.Get(18).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
this.fpSpread1_Sheet1.Columns.Get(19).CellType = textCellType28;
|
||||
this.fpSpread1_Sheet1.Columns.Get(19).DataField = "tag";
|
||||
this.fpSpread1_Sheet1.Columns.Get(19).VerticalAlignment = FarPoint.Win.Spread.CellVerticalAlignment.Center;
|
||||
numberCellType10.DecimalPlaces = 0;
|
||||
numberCellType10.MaximumValue = 10000000D;
|
||||
numberCellType10.MinimumValue = -10000000D;
|
||||
this.fpSpread1_Sheet1.Columns.Get(20).CellType = numberCellType10;
|
||||
this.fpSpread1_Sheet1.Columns.Get(20).DataField = "idx";
|
||||
this.fpSpread1_Sheet1.Columns.Get(20).Tag = "idx";
|
||||
this.fpSpread1_Sheet1.DataAutoCellTypes = false;
|
||||
this.fpSpread1_Sheet1.DataAutoSizeColumns = false;
|
||||
this.fpSpread1_Sheet1.DataSource = this.bs;
|
||||
this.fpSpread1_Sheet1.Protect = false;
|
||||
this.fpSpread1_Sheet1.RowHeader.Columns.Default.Resizable = false;
|
||||
this.fpSpread1_Sheet1.SelectionPolicy = FarPoint.Win.Spread.Model.SelectionPolicy.MultiRange;
|
||||
this.fpSpread1_Sheet1.ShowEditingRowSelector = true;
|
||||
this.fpSpread1_Sheet1.ShowRowSelector = true;
|
||||
this.fpSpread1_Sheet1.ReferenceStyle = FarPoint.Win.Spread.Model.ReferenceStyle.A1;
|
||||
//
|
||||
// fJobReport
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
@@ -1062,13 +1059,13 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.dsMSSQL)).EndInit();
|
||||
this.cm.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.fpSpread1)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.fpSpread1_Sheet1)).EndInit();
|
||||
this.toolStrip1.ResumeLayout(false);
|
||||
this.toolStrip1.PerformLayout();
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
|
||||
this.splitContainer1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.fpSpread1_Sheet1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace FPJ0000
|
||||
{
|
||||
public partial class fJobReport : FCOMMON.fBase
|
||||
{
|
||||
int curLevel = 0;// Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
string fn_fpcolsize = "";
|
||||
public fJobReport()
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace FPJ0000
|
||||
|
||||
dtSD.KeyDown += dtSD_KeyDown;
|
||||
dtED.KeyDown += dtSD_KeyDown;
|
||||
|
||||
curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
}
|
||||
|
||||
void __Closed(object sender, FormClosedEventArgs e)
|
||||
@@ -144,7 +145,7 @@ namespace FPJ0000
|
||||
|
||||
|
||||
//일반사용자의경우에는 상태를 변경하지 못한다.
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
|
||||
if (curLevel >= 5)
|
||||
{
|
||||
btSave.Visible = true;
|
||||
@@ -263,9 +264,16 @@ namespace FPJ0000
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
string request = cmbUser.Text.Substring(cmbUser.Text.LastIndexOf('(') + 1);
|
||||
request = request.Substring(0, request.Length - 1);
|
||||
if (cmbUser.SelectedIndex == 0) request = "%"; //전체검색 201028 - chi(임현대)
|
||||
if (cmbUser.SelectedIndex == 0) request = "%";
|
||||
|
||||
|
||||
//사용자 목록다중선택으로 인해 처리
|
||||
@@ -314,6 +322,21 @@ namespace FPJ0000
|
||||
//else
|
||||
// this.ta.FillByTagOnly(this.dsMSSQL.JobReport, dtSD.Text, dtED.Text, request, FCOMMON.info.Login.gcode);
|
||||
|
||||
|
||||
int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
|
||||
if ( request != FCOMMON.info.Login.no && curLevel < 5)
|
||||
{
|
||||
this.fpSpread1_Sheet1.Columns["ot"].Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.fpSpread1_Sheet1.Columns["ot"].Visible = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
RefreshTime();
|
||||
FPUtil.ColSizeLoad(ref this.fpSpread1, fn_fpcolsize);
|
||||
FormattingData();
|
||||
@@ -824,6 +847,11 @@ namespace FPJ0000
|
||||
|
||||
private void toolStripButton11_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(curLevel < 5)
|
||||
{
|
||||
AR.UTIL.MsgE("사용 권한이 없습니다");// util.MsgE("");
|
||||
return;
|
||||
}
|
||||
var f = new JobReport_.rJobReportUser();
|
||||
f.Show();
|
||||
}
|
||||
@@ -983,5 +1011,10 @@ namespace FPJ0000
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void fpSpread1_CellClick(object sender, FarPoint.Win.Spread.CellClickEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,225 +130,227 @@
|
||||
<data name="bindingNavigatorMoveFirstItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
vQAADr0BR/uQrQAAASpJREFUOE9jGDygcNbz/00Lnv/PnPj4P1QIA4S3P8Apx5A789n/VUfe/8elKL77
|
||||
wf/ghmu4DciY8vT/wn0fsCqK73n4f+n+///9qy/gNiCh58n/aVveYyiKaL8P1pw56/9/r9ITuA2I7Hr0
|
||||
v3f1BxRFoa33wJpb1wFt7/z73yX/AG4DApsf/q+b/w6uKLjl7v9Fe///7wBqzpjz879d3c//9hnbcRvg
|
||||
UXX/f/60NyiK7Ipv/0+f8/u/f9e3/zqF7/5bJKzHbYB96d3/2ZNfYyjSTzn/36ToxX+VrE//jSOX4TbA
|
||||
Iu/O/9T+11gVGSSd+C+b9vW/bvA83AYYZt3+H9byEqci/dTL/zV8p+E2QCftxn+/6od4Fal4TMBtgFPu
|
||||
lf8gBXgVDULAwAAA8HbAq6XlmnAAAAAASUVORK5CYII=
|
||||
vQAADr0BR/uQrQAAATFJREFUOE9jYBg0oHDW8/9NC57/z5z4+D+6HAyEtz/AKceQO/PZ/1VH3v/HpSi+
|
||||
+8H/4IZrWOXAIGPK0/8L933Aqii+5+H/pfv///evvoAhBwcJPU/+T9vyHkNRRPt9sObMWf//e5WewG1A
|
||||
ZNej/72rP6AoCm29B9bcuu7/f//Ov/9d8g/gNiCw+eH/uvnv4IqCW+7+X7T3//+Odf//Z8z5+d+u7ud/
|
||||
+4ztuA3wqLr/P3/aGxRFdsW3/6fP+f3fv+vbf53Cd/8tEtbjNsC+9O7/7MmvMRTpp5z/b1L04r9K1qf/
|
||||
xpHLcBtgkXfnf2r/a6yKDJJO/JdN+/pfN3gehhwcGGbd/h/W8hKnIv3Uy/81fKdhlQMDnbQb//2qH+JV
|
||||
pOIxAaccg1Pulf8gBXgVDUoAAPB2wKtYlLYeAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="bindingNavigatorMovePreviousItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
vQAADr0BR/uQrQAAALZJREFUOE9jGDogvP3BfyiTdBDf/eB/cMM18gyI73n4f+n+///9qy+QbkBE+32w
|
||||
5sxZ//97lZ4gzYDQ1ntgza3rgLZ3/v3vkn+AeAOCW+7+X7T3//8OoOaMOT//29X9/G+fsZ00F9gV3/6f
|
||||
Puf3f/+ub/91Ct/9t0hYT3oY6Kec/29S9OK/Stan/8aRy0g3AAQMkk78l037+l83eB55BoCAfurl/xq+
|
||||
08g3AARUPCZQZsBgBQwMANAUYJgEulBVAAAAAElFTkSuQmCC
|
||||
vQAADr0BR/uQrQAAALtJREFUOE9jYBgyILz9wX90MaJBfPeD/8EN18gzIL7n4f+l+///96++QLoBEe33
|
||||
wZozZ/3/71V6gjQDQlvvgTW3rvv/37/z73+X/APEGxDccvf/or3//3es+/8/Y87P/3Z1P//bZ2wn3gAQ
|
||||
sCu+/T99zu///l3f/usUvvtvkbCeNANAQD/l/H+Tohf/VbI+/TeOXEa6ASBgkHTiv2za1/+6wfPIMwAE
|
||||
9FMv/9fwnUa+ASCg4jGBMgMGLwAA0BRgmCws/7cAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="bindingNavigatorMoveNextItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
vQAADr0BR/uQrQAAAKNJREFUOE9jGHygcNbz/1AmeSB35rP/Cd33yDckY8rT//P2//6f0HWHPEMSep78
|
||||
n73v1//OrX//u5VeJt2QyK5H/6ds+/W/ZOnf/wnT//63yT1LmiGBzQ//t659D9ZsXPLlv3T0tf/GkcuI
|
||||
N8Sj6v7/krnv4JoVXXpIc4F96d3/gS3PyNMMAhZ5d/7bFFwhTzMIGGbdJl8zCOik3SBf81AEDAwAoH5f
|
||||
oAc0QjgAAAAASUVORK5CYII=
|
||||
vQAADr0BR/uQrQAAAKRJREFUOE9jYBh0oHDW8//oYiSB3JnP/id03yPfkIwpT//P2//7f0LXHfIMSeh5
|
||||
8n/2vl//O7f+/e9Wepl0QyK7Hv2fsu3X/5Klf/8nTP/73yb3LGmGBDY//N+69j1Ys3HJl//S0df+G0cu
|
||||
I94Qj6r7/0vmvoNrVnTpIV4zCNiX3v0f2PKMPM0gYJF3579NwRXyNIOAYdZt8jWDgE7aDfI1D00AAKB+
|
||||
X6Bjq5qXAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="bindingNavigatorMoveLastItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
vQAADr0BR/uQrQAAASxJREFUOE9jGFygcNbz/1AmBgDJNS14/j9z4mOcahhyZz77n9B9D6sCkNyqI+//
|
||||
h7c/wG1AxpSn/+ft//0/oesOhiKQ3MJ9H/4HN1zDbUBCz5P/s/f9+t+59e9/t9LLKApBctO2vP/vX30B
|
||||
twGRXY/+T9n263/J0r//E6b//W+TexauGCTXu/rDf6/SE7gNCGx++L917XuwZuOSL/+lo6/9N45cBtYA
|
||||
kqub/+6/S/4B3AZ4VN3/XzL3HVyzoksPXDFILn/am//2GdtxG2Bfevd/YMszDM0gAJLLnvz6v0XCetwG
|
||||
WOTd+W9TcAVDMwiA5FL7X8O9hBUYZt3GqhkEQHJhLS//6wbPw22ATtoNnJIgOb/qh/81fKfhNgAfcMq9
|
||||
8l/FYwIYQ4UGBWBgAAC+0b+zuQxOnAAAAABJRU5ErkJggg==
|
||||
vQAADr0BR/uQrQAAAStJREFUOE9jYBhUoHDW8//oYjAAkmta8Px/5sTHONUw5M589j+h+x5WBSC5VUfe
|
||||
/w9vf4BVHgwypjz9P2//7/8JXXcwFIHkFu778D+44RqGHBwk9Dz5P3vfr/+dW//+dyu9jKIQJDdty/v/
|
||||
/tUXcBsQ2fXo/5Rtv/6XLP37P2H63/82uWfhikFyvas//PcqPYHbgMDmh/9b174HazYu+fJfOvraf+PI
|
||||
ZWANILm6+e/+u+QfwG2AR9X9/yVz38E1K7r0wBWD5PKnvflvn7EdtwH2pXf/B7Y8w9AMk8ue/Pq/RcJ6
|
||||
3AZY5N35b1NwBUMzTC61/zXcS1iBYdZtrJpBACQX1vLyv27wPKzyYKCTdgOnJEjOr/rhfw3faTjV4AVO
|
||||
uVf+q3hMAGN0uYEFAL7Rv7NmXVYYAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btAdd.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
vQAADr0BR/uQrQAAAUpJREFUOE9jGLzg7gL2/7fmcf6/Oofr/8UZvP+hwsSD60CNfx41/v/zsOH/yckC
|
||||
pBtwfjov3ICDPSKkG3B8kiBQc93/Pw+q/u9oFydswKWZPP/PTuX7fxKo8Ui/0P993SJAzeX//94r+r++
|
||||
Qeb/qhq5/0srFf/PL1X+P6tIFdPAU0B//nlYD9RUC8SV///cKwHivP9/72b+/3sn+f/f23H//92MAOKQ
|
||||
/5NyNDENONQrDHbu3/ulQI0FQI3ZQI2pQI0J///digZqDPv/70bQ/3/X/f53peliGrCzXeL/lmap/+vA
|
||||
zpX/v6RC8f/fWzFAjeH/p+Zp/J+QpfW/O0P3f3uq/v/mREPCYTIb6E+Qc//dCPjfk6FDWAM6APnz3w1/
|
||||
IPb735qsT7oB3em6YP+CcH2cEekGtCQZ/G+IN/xfE2v8vzLahHQD6AQYGAAkI9iedfyIaQAAAABJRU5E
|
||||
rkJggg==
|
||||
vQAADr0BR/uQrQAAAVdJREFUOE/Nz0tLAmEUBmB3kWRoCUVEISFUJGb1OywiKrDsIpZdkJAkDUvDQkij
|
||||
UKSbVIvatKhNi9oERRAGEQXhjJdp7Hd83/eGs2jhLGQ20QtndTgP71Gp/m0KZ1XInlTjM6XG+4EG5fuK
|
||||
yaTUIN8bIMUQ0gmtcuBtX/MLPMT0yoHnuA6kuA4iruI20lAZ+DiswWuyFum4Dk+7dbiP6kHEFVDBg+tQ
|
||||
My4DLbjwG3DqbcORxygHXxJakGIQRFwDEf0gwjKI4AYtzIHmHaA5Oxg/CsYPIb7YIQced+qluvTLCyIs
|
||||
gRYWQPNO0NwkWNYGxg+DcYNgGSu2Z0xy4C7SiJtwE66kuq049xlAs2Ng/AiS7nbszXci6jIh4jQjPGWR
|
||||
A+U59hiluowbQMzVVfmgPKU/GdcPxlmx5TArB6KzJunf0gTtPcqBzeluhCYsCIz3wm/rUw78WX4AJCPY
|
||||
nlwVm9EAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="btEdit.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEvSURBVDhPpZI/S0JRGIed+i6Nbk0t0iCuSkuDi1MfIKfm
|
||||
+gAOQktTQkMggYtRkwgidKmgyQwMCgqz0CivvvK8cK7neG4KdeHhHs45v+c9/xLyz08Ft713OQ+6SqXV
|
||||
kfLlnXJw1lSK5VrERqGkMB4JCCLpvQ7lZfDlQJ+B4EnwI9nTkbYdAZMbjxOPq4eJPH1MvXC2sD8XsOzP
|
||||
0bcX/C3MXEfAfmzBsnCnP10uWBWu3IS+gJOm0w5fHCZiw0aQzu3GC0xYgm2R+poTRnh8HeqNOALu920w
|
||||
9MK0F8NGkMrs+ALewqrwUXss3ed+vKB6H+rh2OT3SjpO0IBgcyvnCjgDBGCq8mcMiQ3FHAGdLB/J4vMF
|
||||
KhoI83LXk6m5gCpmufbyOWlgv0BVIMx4JPj7JzIDGHRUPz2nxiQAAAAASUVORK5CYII=
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEuSURBVDhPpZKxS0JBHMff1P/S2NbUIg7RqrQ0tDj5B9jU
|
||||
nH+Ag9DSlOAQhNCi6BRBBD1SaDIDg4JCLVSqpz/5HJzdz3vp4MH3vcfdfT73e3cXyJot4NHs9qUSdkxK
|
||||
t20p1lsmJxc3JkfFq3m2MwUTxucCQCTd96G8DcYq9NkAnoc/kiqPzLcSMPn6eeKl8TSRl8+pB6cyx38C
|
||||
yv4afXvgfzBzlYD/cQXL4HZvulywCi49RL6AnabThWv5IBa2gt10Nl5gYQn3RaobCkZ4dh+ZE1ECzvdj
|
||||
MPRgvhdhK0jsHfgC7sIq+PTuVzqvvXjB5WNkNsfNYa5gxgFtEOwk01rAHiAgdlXejCFxw2JKQCflI1m8
|
||||
voQVbYC5uZtbCV2BLdctn50m/C9hVQKs7sE6bQYYdFQ/+SVRqQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btDel.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
vQAADr0BR/uQrQAAAW9JREFUOE+1kE0ow2Ecx3dV3krt4oJaOSCTvIRkMqSxyITIzCQHDouEdnFwIOVC
|
||||
DrhIDiQl5UTiNG/z2ppafy1S2gX/uDwfY6i1v7Hie3nqeb7fz+/7/FR/Ilwn0G0Exw4fV5GJlXlEZxXC
|
||||
rIet9bAQvB5Ymgn2sLYAvSZEux7RUQFzE4qQt4bCXAYjPaHvnDoCkLpsRGMB2JqCTGLIijDlwqQ9bEMV
|
||||
i9OIytR3EMNWcJ/BWH8A6j8/bOGFxwXNxYEvGbMQ9XnQ1/K78KfY3/VXzkMY0qFGG2H4RoLGQshJQNbG
|
||||
86CNhdrsX9a/uQZTPhQl4rMY4OLofbl3aX7I8uwPC7y/g1YdjyVJuEvT8e1tfwUYteHUxCCfHChDeHmG
|
||||
QQvokjlOU+PbWA0x3pZnILVVI3uvQyHsbiLnqnGmRCF1NYD8pDhpRxOH7HQoAKZGkFKjceszQbpSrumX
|
||||
bO+G80MFwKUTxgfgcO/b8D9IpXoFiiMDHIQm0skAAAAASUVORK5CYII=
|
||||
vQAADr0BR/uQrQAAAWtJREFUOE+1kE0ow2Ecx/9X5a2UiwtKOSCTmJBMhuQlMo3IvCUHDouEXHZwIOVC
|
||||
DrhIDiQl5USy07zNa2tKf2laaRf84/J8xBCetab4XL/f76fn+SnKX4DrGLqrwbHDzywkWJlHdJYjLEbY
|
||||
Wg8q4eYKlma+d1hbgF4TotWIaC+FuYmAktcXCksx2HrknBOHX1KbiTDngrXhW0kMdSBM2TA5Io+/wuI0
|
||||
oiz5TcRwB7hPYazfLx3rDz7+gCsXNBb4v1SdgajTQ19TaOMP2NtFmPSIilSo0v1y7FHBnAdZMWi6aO51
|
||||
kVCTGZoEzzWYciA/Dl9bBZwfvh3XmxIJy7PBJdx5odnAQ2E87qJUfPbtzwGjVpxJEWjH+4ElPD/BYBsY
|
||||
EjhKicW3sSoVb0vSUFsq0W6upUxhdxMtOxZnYhhqVz1oj3JJUZSdpCg0p0POmLKhJofjNqaDeikX3tFG
|
||||
uuHsQM65cML4ABzY5fA/eQGKIwMcVjm2bAAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btFind.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btImport.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE8SURBVDhPnZI/S0JRGIf9Oo19ARdziDZBGmwRx5amFsG5
|
||||
BolahJbWmkKwKYQ2BZGISohABIWCjJDsgmj3xHPivfc99yCCB56r98/vOed9z0mZNUZKDx48vU1N42Fg
|
||||
uez0zfldz3J03bYc1hoOjoQbgkhG4x/zMQkceKY5vh2b3YPTWCICPm4NQ49m/zfiMwitwJFwYdnfwcwL
|
||||
l06yngD4NlcsxwLqTQoIa8HNyyJipYDgWbcQSQT6dPU49wV0WgTF6pap1AtWoEEwnISRYDu/7wtYalLA
|
||||
f9ACdsMRsLfsgtSLhDC/ugQEF/f/gszO3nIBjZIwIaA8wjB4/1oukE6zVAQ6WOssLAjS2bwrkB5ogZAU
|
||||
MJkj4FQ9v46shJf66AIzCrzn5G5sZmIBK0AisMdAp4F6BWYm7JyD9Ycxf8jQQxybOGd5AAAAAElFTkSu
|
||||
QmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE5SURBVDhPpZK9S0JRGIf9dxr7B1rMQdwCadBFGl2aXILm
|
||||
GiRqEVxcc4rApgjcCiQi+gAJRFBQUBGpLkh2Tzwn3ut570mCOvBcvR+/55z3PSdh/jAS7uDB4+DNNO67
|
||||
ltNWx1Sbz5aDsxtLqdJQKAk3BJH0x+9mNAsUPHM5vByb7d3jpUQEfHzdCz2uOp8RkyC0AiXhwrJfg7kX
|
||||
3jlKeQLg263C3lJAvXEBYVdw0V5E/CogeHKbiyQCfao/fPgCOi2CQnnT7J/nrMAFQW8WRoJ0tugLWGpc
|
||||
wH9wBeyGErC37ILUi4Qwv24JCGp334JkJr9aQKMkTAgojzB0h9PVAuk0S0XgBiuthQXBRiqrBdIDVyDE
|
||||
BUymBJyqp5e+lfx0fJlR4D0nd209qVeARGCPgU4D9QrMTFidg/+ML8jQQxyg3treAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btOpenFolder.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
|
||||
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
|
||||
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
|
||||
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
|
||||
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
|
||||
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
|
||||
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
|
||||
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
|
||||
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
|
||||
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton10.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAALwSURBVDhPhZJZTxNRGIZ7JT/BoBdekhiFKEaNXigIWMAE
|
||||
NwSCyFYKAQEJ1GAi1hSMyGJAAiRqCETjhRpwgQKWrZTSNhQDMpZF9i1hqUCXGehMeT0zrYAJiV/y5Fyc
|
||||
eZ/M986I+Al8qI67UqxXhZXofwfJ9TQ5GYFS/jQwYcU6JuSZljov05QfDX9/QAjtneAnPZplC7NKURRn
|
||||
tm3CbN1l1cLDYHjRgrwvs4gqGbGL05Ue7qhrQgu1yxRl4nTTDhhmWBhmWeinWWintqD+tYkWkw2bLNA4
|
||||
QiPv0wwSX1D0P5IgeQu9Yd9C/xyH73MsOVn0CZItdI9v4pvJTgRO9C9yMCw4UKCchf+DjndCOLLUb/KW
|
||||
PHxbWnUDiZU3Udlah/z6UvjLveFHEBecQ6DiNMoay4RVrAyLpTU7AmO7WUEQUez/sWOoCU1jr1GpzxEk
|
||||
sRUhyHkbg4y6KEiqryKhOgGNg0tooqz4+mMD66SnIEUPIwjE5WIPH3kmpx/twpshBYrU6YIkriqUhK8h
|
||||
5WUyNOM2YZX2MRoq0sOazYGg/F6XgJ/gwm4mqyYexnEtqg338bQtG5GllxBXEQ7jtB1GUixfsGbC1YmZ
|
||||
CAIVewQXHskdZ3KPIKZcjP4JHQq6UqFQZiHqeQDq1J8xMM/CSIrVTTnQS1i2OOD/2C04KfOU+soOI6M2
|
||||
GrerghFddlmQZCljIKtPJm8SAP6+f5ZDH/+JCRZSpE+m1iXwlR2c95UdIg95wjfHE9eLApD2Kh4akwoF
|
||||
qlykfoiHpCoCRiIwkH9DTwSMw0kE6t0VLmb2MIvrDAbnOYHu0QXcq0lBEglKq6OQXXt3547HvsURQcOu
|
||||
gLfNmXcF/8PGr5C8R3A2q9Ou0g1u7/fwflDDo87jsY1Wd5wUmdI2ObNht3Tqh5yTKzQml2mMu1mxOgT4
|
||||
5q0MhwFqxEnT9LrXneaf7rhIdCqlNc1H0tJ2Qqoy+0gbmB2SXHj/RdLAeEma144lNLd7xysTRSKR6A+3
|
||||
VJ80gqHE3AAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton11.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton12.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton13.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton14.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton9.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton3.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
|
||||
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
|
||||
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
|
||||
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
|
||||
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
|
||||
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
|
||||
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
|
||||
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
|
||||
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
|
||||
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="dsMSSQL.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<data name="toolStripButton10.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAL4SURBVDhPhdHrT1JxHMdxHtWf0KwHPXRrBStatXpQkhpq
|
||||
m91MXZmiiK4buaTZltGIlqk0rQlbNaer9aCadkG8YBdABBZ0UVQqb4C6ZZHK5Rw859CnnYNhtrV+23vn
|
||||
we/8Xtv39+PxeDxe2iVT0f46uzG73v4jXWknsuvtJJeG/TrI7DobmXnD6t6lsDRuyHm0ij2zYmVc67PM
|
||||
BsnvbrebCYSjCISW+x5kIzEyE0T1cx/y6z0R8RnD6hVAVo111u0eYmyTFBxeGg4fDfskDevEIkxfouga
|
||||
DiNKA3oPgeqnXpTcchMrkHRlF7EQWYTLz+Cdn4bLT+MthyzCPBpFz3AEUToG1wwDxzQFtcEH0cVXD7nD
|
||||
eZqU8aPKnJ8y7WGUNB1BU3crrrZpIFLykaLkQ6zeiTTVNjToG7hRQiSNr3MRpBWaaQ7IrRM9eTXYgY7P
|
||||
99Bkr+SQwtuZqHxQgLOt+ZDqDqBYVwz9x6/ocIfwYmAB8+Eo0lV9JAeIG8Wr+Uo5Y//0BvcHVag1neGQ
|
||||
Im0WpLqDKL9TBstomBvl5WcCRg+BuTCF9Kv9cYBdGTVmsqJZAueoFTrHBVzvPY88zV4U3c6BczICp5cG
|
||||
e8GWsfidBMIU0lR/ALsvK6ntVetR0CiGa8wG9ZuTUBkqkH8zFa2mZ/gwRcPpp2GboNA/QWE2SEF0ZQnY
|
||||
okiSCRXrcLblGI5rM3CsYR+HVBgKoGgrQ54mFey+y8fgLfvEXhpBkoZAbo0DQsWaKaFiLYSKJAgrk3Co
|
||||
NhWn7kpgGTZCbazCyccSSLW5cPoYOCZp2L00SCoGgdy0PMIeeR85M0/i4xTDZf40jXPN5SjV5kKmy8f5
|
||||
ltOJPbbIIgOBvH0ZYDV/YBn4X2F2hLI/gB0VryM9/R9+/v3jvxoc9sQ2FepDCWBLee+4dyESfG0biI1/
|
||||
IzA+S2B0qW8hiou9+RDJ4P3gSIwgiPnkE51DCWBrefcpgbSrd7PMGBDI2slEpfH4v5O2k8nSzrmNxZ0v
|
||||
+RJDCXv2F6ujnydZP57oAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton11.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton12.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton13.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton14.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="cm.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
@@ -400,9 +402,9 @@
|
||||
<value>499, 17</value>
|
||||
</metadata>
|
||||
<metadata name="fpSpread1_Sheet1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>563, 17</value>
|
||||
<value>561, 17</value>
|
||||
</metadata>
|
||||
<data name="dateTimeCellType1.Calendar" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<data name="dateTimeCellType3.Calendar" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAEAQAAACZTeXN0ZW0uR2xvYmFsaXphdGlvbi5HcmVnb3JpYW5DYWxlbmRh
|
||||
cgYAAAAGbV90eXBlEW1fY3VycmVudEVyYVZhbHVlD3R3b0RpZ2l0WWVhck1heBpDYWxlbmRhcittX2N1
|
||||
@@ -412,7 +414,7 @@
|
||||
AAD/////AQgAAP////8AAQgAAAs=
|
||||
</value>
|
||||
</data>
|
||||
<data name="dateTimeCellType2.Calendar" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<data name="dateTimeCellType4.Calendar" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAEAQAAACZTeXN0ZW0uR2xvYmFsaXphdGlvbi5HcmVnb3JpYW5DYWxlbmRh
|
||||
cgYAAAAGbV90eXBlEW1fY3VycmVudEVyYVZhbHVlD3R3b0RpZ2l0WWVhck1heBpDYWxlbmRhcittX2N1
|
||||
@@ -428,90 +430,89 @@
|
||||
<data name="toolStripButton8.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANPSURBVFhH7dhZTxNRHAVwPoRx3yuyKWUvqyJu4BqNiYnx
|
||||
C/giaowRQSiibC0Uyg6CyqKSuEaEQvdCK7tPqAmokWDUiFGgyCrHO+k0oT609w4JvvQk9/n+MjPn/ifX
|
||||
wx133BGQh8dfX3hwzGy9f7QfDUfIOtyH+kN9qEvoRW18L+4d7MHdAz24s5+sfd2o2duN6rgu3N7TharY
|
||||
TlTu7kTFrlcojyEr2oKyKAtKIy0oiTCjONyMIkkHlGFkhbajMKQdBcEma36QIZHf3nWWGQdFkAm5gaYJ
|
||||
fnvXWW5cfqAJeQFG8Nu7zv/AycUswCXgyqLNUEbokSdpQ4FEh6LwDiqc3N9AD1zKkyuM1KL/8UfMTs2j
|
||||
p/ED5CEaKpxsJwNQKI57cu2V77A4xfFaKlzuDj09UAiuONKER5e6sfBngacBP0cmIQtTUeFy/BiArLjS
|
||||
qA5UnTJgemKWpwFzM/OoOWuEIthIhcv21dED2XCkFLFafH8/ztNseSHtR16wjhqX5cMApMVxR4kiXIO3
|
||||
ms88y5auhiFy8KqZcJneLEBKXGG4HqYKx1IM94+S766VGZfppaUH0uCKIkgpLjqWYuzLbxTGqcl3Z2DG
|
||||
3drOAHSFK4nkS2Gd42m2UlSfMYIMfUG4m54aeqAzHDe+FGE6DHV85Wm2PEvpgzxIKxiXsY0B6AzHzdb8
|
||||
UB0G2x2BT5N7IQvUCsbdEKnpgc5w3OBXSkwoP6F3fMXT86g8TUBivSBc+lYGoDOcffArQvRoTOxyKMkv
|
||||
UhJ5TCtk/jpmnHRLGz3QFc4+W2VBGuhL3/A8Wz71jSJT3MyMS9vMAqTA2c+5LLEKA20jPM8WS+0gMnxb
|
||||
mHBpm1rpgbQ4rhDyAANyJCp8GxrjebY8SepBhncrNS51IwOQFmdvK/fNKRM0mBpf9LNASlN6kqC81FS4
|
||||
6xsYgCw4e1uz/NSoP2d2KM2P4QlIfZqocCnrVfRAVpy9EBk+KmiUAzzPluyIFipc8joGoBCcvRBS75fo
|
||||
JH8zM5NzsNQNIlXURIW7traFHigUZy+E1LMFKaLnBNeMdFEbFS5pDQtwCTjaQvyLS1rdTA/8H7irqxiA
|
||||
BGddbtzllU30Vx/cRQ53V7KcuCsrms7z27vjjjv08fD4CwlIPe+HvHrCAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANNSURBVFhH7dhnT1NRHAZwPoRx74osZZTRUkARFzijMTEx
|
||||
fgHfiBpjRBCKIKuFQtkgoEBVElwRoaWTLkahvkJNQI0Eg0aMsqc85ia24TYBzrkk+KbPJ/jl3Puc/8nf
|
||||
w8Mdd9yhz9Ozb689OWMZf3zaDsUpOxQne1B/ogd1cd2oje3Go+M2PDxmQ81RG2qOdKH6cBeqYjrx4FAn
|
||||
KqM7UHGwA+UH2lEW1Y6ySCtKI6woEVlRHG5BkdCCQoEZ8jAz5KEmFISYkB9sHM/jG+JdHUtmjXGQ8Y3I
|
||||
CTKOuTqWzFrj8oKMyA1sg6tjyfwPnDSABrgKXGmkBfJwPXIFrcgX6FAoNBPhpP4GciBXHHNyBSIt7M8+
|
||||
Y3ZqHraGT5CGaIhwkv0UQK445uRMFR+wOEWxWiJczj49OZALrkhkROONLiz8WXDifg1OQBKmJMJl+1EA
|
||||
aXElEWZUXjBgemzWiZubmUf15TbIgtuIcFm+OnIgHc4CebQWPz6OOnFMXovtyA3WEeMyfSiApDjmKpEJ
|
||||
NXiv+crCdSr6kROkpsJleNMACXEFQj2M5exSDNiHIQlTUeMyvLTkQBJcYbgRjdfZpRgZmkRBjBqyYAM1
|
||||
7v5eCuBKuGLRv1KMzzlxTCmqLrUhj88Nl+6pIQcuh2PGlyxMh37zNyeOycukHkj5Ws64tD0UwOVwzGzN
|
||||
C9Whz8QGvkjshiRIyxl3j6cmBy6HYwa/XGBE2Tk9+xNPz6PiogGSAD0nXOpuCuByOMfgl4Xo0RDfySrJ
|
||||
76FJSKNUkPjrqHHiXa3kwJVwjtkq4WugL3nnBDL50jOMjIBmalzKThogAc5xz2UGKNHbOshCWmv7kObb
|
||||
QoVL2aEiB5LimEJIAw3IFijxvX+EhXyeYEOat4oYl7ydAkiKc7SV+efkcRpMjS56LEzPo+S8FuleaiLc
|
||||
3W0UQBqco62ZfmrUX7GwSvNzYAxinyYiXNJWJTmQFucoRJqPEhp5rxPIJCu8hQiXuIUCyAXnKITY+w06
|
||||
FP2YmZiDta4PybwmItydzS3kQK44RyHEni1I4r1CMq8ZqbxWIlzCJhrgKnCkhXDFJWxsJgf+D9ztDRRA
|
||||
Zley1rib65vIVx/MIofZlawl7ta6pquuDnfccYcgfwEJSD3vAJhh2AAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton7.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANSSURBVFhH7djZTxNRGAVw/gjjvq9tVWgBAbUguO+aGE18
|
||||
8N0XFROj4oYitHbB0haL4i4qGhUTRew27bS1pRSEJ4kkKCZuiRhJpEQE5TjDTKPEpL13TPClJ7nP95e5
|
||||
c+a7mZRkkklGQu5saSus3RyM3t7UilsbubXhOW6uf46adS24sbYF19c049rqZlxdxa2VEVxZEcHl5U24
|
||||
VNCEi/lhVC8L40JeI87ncksdQtXSEGxLQji3OIjKnCCs2c9gyeLWogDMmQFUZPijZ9PZfeL2iTPKOJjS
|
||||
/dCr/L3i9okz2rizKj/KlT6I2yfO/8AZ02iAhLiLBWHY8nwwq12oVLOoyg1JxhlTWXIg6ZOrzGXRer8L
|
||||
A99+oK3uDSxLGck4w0IKIPGxbmXxZwLVL2HO8UrC6Rd4yYGk75w1n0HP+z6RBwz9HMK9/RGYs33UON18
|
||||
CiBpIWzqIK7vCgwfcSzfo4Oo3s7CnOWnwp1ReMiBJLhYW61LfHh0vFXkCfn8phemPCcqMv3EOK2cAkiK
|
||||
ixXClOVBpPaVyBPSwX6EPt1BjNPIaIAUuFghjNkOdEW6RZ4Qr60dOqWbCKeZx5ADaXF8IcxZ3LuW70TP
|
||||
uz9KMwTcLQzjTKo7Ia5sLgWQFhdrqynDh0s7WQz2/y5Nf+8ArBvc0C/0xMWVznGTA6XgYm01qBg8PNIi
|
||||
8oR0+D6iVGGPizs9mwIoFccXQq9kUFc0EvjS+4EDOuLiSma5yIFScUYliws7vH8dsXmdC1oFExd3aiYF
|
||||
UAquXOWDQW3Hl7dRkSaUpHZPI0rljoS4kzOc5EBaHP+d0ygb8DrySaQJYSwvcFpuJ8IVT6cBUuK0qU40
|
||||
3uwUWULamfcoUTwhxhVPc5ADaXC6NDceHGoWWUK6X3+FJrMBGjlDjDsxlQJIijOkeVG1zTvistDPXRYs
|
||||
613UuONTKIAkOH58aVVPR5aCu27V7A6iVOakxh2bbCcHkuD42WoqcIo0IXwpSmR2SbijkyiAJDh+tpbN
|
||||
t6Ppdie+9w0ifKsTp+RPJOOOTHxKDiTB8YNft8AzPCFOyh7/05PjcUUTaIAEuESDnxZXNL6BHPg/cIfH
|
||||
UQA5XHS0cQfG1pP/+uB/5PD/SkYTd3BM/V5x+2SSSYY8KSm/AHvBPpKbf2MsAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANRSURBVFhH7dhZT5NBGAVgfoRx31daWVpAUCgI7uCaGE28
|
||||
8N4bFROjgqKApaVspQXZXZBNo2LiAm3pR7+2tpSW5UqCCQKJookYSaRGFOGYIWm1GGDmM4Gbnl/wZCZn
|
||||
3skbEOCPP/6w58HR7uSGIzZ3/eEu1B3qQt3BTtQmdaImsQP3D3Sger8L9/a5cHevC3f3OHFntxO3d7Wj
|
||||
KqEdlfEOVOx0oDyuDWWxbSiT2VEaY0dJtB23dthQvN2GoqhX0Ea+gnabFZoIKwrDLe6CMP78dMeMmWcc
|
||||
1GEW5Egto9MdM2a+cQVSC/IlZkx3zJiFwOWFsgApcZUJDpTEmaGRtaBYxqM01i4YlxfC0wNpcOTkimN5
|
||||
dD0ewM/vv9DdOAhtDCcYlxvMAKTBTV3rMR5/x1rRC812kyBcTpCJHkiF2+lAUTyHkaFvXuDkxCQeXXBC
|
||||
E2Vmxqm2MgBpcKQQJTIbqk9bp67Ykx/ucVSc4KGJtDDhssWt9EAanKetRdFmPEvr8gJJPg+OQh1nQGGE
|
||||
hRqnFDEAaXGeQqgjW+FseOuDfMN/RE6YnhqnCGQBMuA8hciL0mPAOeyDNJX0QCUxUuEUWzh6ICuOFEIT
|
||||
aUVhvAEj7/8qzSTwMNmB7BDjnLiszQxAVpynrepwM6pO8Rgf+1OasdGfKDpoRE5w66w4+SYjPVAIztPW
|
||||
XCmHp6kdXiDJG/NHyMW6WXE3NzIAheKmfiUSDo0pvsBe0wfIxfpZcZkbWuiBQnF5Eh7lJ03/XLEmsQVK
|
||||
MTcrLmM9A1AILl9qRq5Mhy/v3F4cKUnD2TbIRfo5cenrDPRAVhx55xSSJvQ7P3lxJJz2NW6KdFS4G2tZ
|
||||
gIw4ZYgBbbV9PrgebgiZ4pfUuBtr9PRAFpwq1Ignl10+uOH+r1BENEEh4qhx11czAGlxuaEmlB43+XwW
|
||||
xtzj0Ca1MOPSVjEAaXBkfCmlzb6lmJhEzRkb5IEGZty1lTp6IA2OzFZ1gsGLIyGlyAzUCcJdXcEApMGR
|
||||
2Zq1VYf2+j78+DYOR10fMkQvBeNSlzfTA2lwZPCrglqnJkR64PP/OjmCS1nGAqTAzTX4WXEpS5vogQuB
|
||||
u7KEAUh2JfONu7j4Bf3qgyxyyK5kPnGXFr04N93hjz/+UOQ3e8E+krxr0cIAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton4.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGJSURBVEhL7ZS9TsQwEITzeoBo4Dko6eiRDpAQ4i0oqWg5
|
||||
aICXoKKjpTQMmgkTs+tLQuhupJHXPzuffYqu22qszta7BeZ0eUXhgsLnD3u/9lf3O3+/kENghPocYKyt
|
||||
uKc52+fLIZF72FctaPQrTBJCIpjbYT7CjJkmNUcwt8Nmw3EwCm+5BUU9+hJReMsOw3jxuF9u347L9fPh
|
||||
YJ3xuaLwlv1FgN69n5SXclnWH6fl6umg32d8rii8ZX+poDBqrP3rizMo9ka9OAre5NZLZcBxlpih/ICM
|
||||
NYToY/E9OIWyV69VLmrifqTDHowGBeNjcXjrpehzqI/EDfUNJ1CHb16P+nDBM2gG00hMrKiphi/2Ulfd
|
||||
pNrhGRRj3a+R8bnqJq8d7j+v93itfpxjfC5vwugfGwy4oJhHoKif8bFwsA5So4w1QTX3nqwfNTFt4aA3
|
||||
Zq5BGmXGTRMaI5jbYfXImHmqA2sw1qJ9ts+XQhGGUbWstfqfj+3zFYUoHMbFuNwLF2C5vATmdKsN6rpP
|
||||
fZjWUaDH7j0AAAAASUVORK5CYII=
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFtSURBVEhL7ZQxTgMxEEVzPUA0cA5KOnqkABJC3IKSipZA
|
||||
A1yCio42pdGs+Ku/b2ezdggVfGlkx/b857G9WSz+VamL1X6J4PjOlJkLGnH5dDCaXz7ujcaa5ZCIMCU4
|
||||
xpbfc/pNn2YRzOhhtonsFJrE6rJwmLdbV61kghgZtBleA2IQ5tDoV2+CxnNB6NXzYbn/OC23r8dtd07j
|
||||
ufCKAvrweVbeynVZrc/LzctRP0/OSDSeC69U0Ijox9ivVjwF9TsmZyCa1sQUVMevimMteZ18gUL3psdS
|
||||
DU0enfzIXWixG0eCPxaHT0LxGbElt1MHx7d5937Smws+BSWELXkDcXEGz6BbVepikvoOn4JGy3y15IzE
|
||||
JO87PPtk2Fd+rCNnJO6ULzngguoBEpTlkzNQtmOCVYH/3lSxryMvlXZPMIMgr7waRtWAM6ha+jWJhgTz
|
||||
eDVOn2b5XWXH3x8r/vno06zMhBVz/sfHvEk7q+zP6At9mNZRIJ9c/gAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="btSearch.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE4SURBVDhPtZPPasJAEMbzPn0FwWA92JtP4NGKB1/DP7ei
|
||||
QSsovkChh7ZBrCfpyR4sikopUgq9StFzM/UbZ5asSS4FfzAkO7vft5udiZMEnSBpk5dhFJmncjdHxXaG
|
||||
A+9K4SbFT1luEwQBbXavVO5d0nI3ovnW5yeiMriiu+kt5asXbABEdgRigAUQDr+aHLU3lxoLl/yPJhvF
|
||||
GsiYJ/vPdX5qPK3bVJ25VFukafztGQNsKHJ791I3w+8KcpNth8XDz5YxACI/gsR1J8sTYcO4UIzwv1gG
|
||||
cTshgJ5IT8hChTMHsHi+v+fvffmxywVwN2FDkdsGEOK2ceu4feQ0tDqKyKMGqDfqjvprLzyswuX7Tf4E
|
||||
dBo6zn/3OB7XHovRyuhQ6+hhYKA9DpL+A1keRebNAhkaJH0OHOcP031C4EjYr6wAAAAASUVORK5CYII=
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEiSURBVDhPY2DAAf6jAXRxVNVIAKYga5bH/7TpTmAMYsNA
|
||||
3EQb3Ab8+/fv/71PZ/5nzXX+f+3T7v+X320H0yCct8Dz/9rTM/8HtGvDDcPQDAIgBSCNOx9NBuOOiw7/
|
||||
u644/N9+ZzLYIKwGwARAkvP2dIJpGN52Y/r/9gsO/zuu2P/f+3Qq3ACQhVhtz5jlBLcBJnb43Qyw5p0P
|
||||
pmB3AcwV6TNcwBLIBmLDKAbAeWQAFAPQbUG2DeYimAsxnA4z4PLnDWD/Hv2AGl0gAAobZAOxGgDSCApt
|
||||
UKiDQh/ZJbDYgQGcBoDiGxTvoPiHpYUt15Gj7y9uL4BSGijFbb81FYy33pgK1gxKyqAUiuJ0ZAAyAJbG
|
||||
QQBXPkDXBwfoCuA60MRpAgDTfULg/+7qPQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADlSURBVEhL7dQxCsIwFMbxnMrZWatzUXRUCo5ewSs4ewZR
|
||||
DyDeQfEETsUbRL7YYNSXNC/UOiQP/kvzyE9KUcQ7y/VJtlHFvQYPjzf50xKsJsFmq81WHq538swMO9il
|
||||
zhALxkWd7kAOJwsnjjPsYNeGs2B14fR5YTYq5O5c1u7sL987iAUjF+6LIjaMKJyDoiAYmVAvn8lsXHij
|
||||
KBhGwDWof4APihqHqQ+OKhg2X3U/n7+9ah88CKY+pM9ndTgbplDbmQtnwS7UtmPDWfDf/jIRLnKhOuzY
|
||||
UMSGmyrBauKE26jiohshHicE2B3dbRrmAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADiSURBVEhL7dVBCsIwEAXQnsq1a62ui6JLpeDSK3gF155B
|
||||
1AOId1A8gSvxBiNTCcTJJM3E2i6SwN9MhnklDW2WRbvW2wu0EepW8PkBf02CE2xks9vD6f4y6jTYg720
|
||||
riKCcVCvP4LxbOXEcQ97sNeGi+Bq4PwzMJ+UcLg+a3uON7NHDHODdZzu2dAgmAMQpzUXGgxTfFAsIJ+W
|
||||
3uhPMAZxBaoH8EExjcPcheMSDOtHPSyWX0ftgwfB3EWitTpcDFNAf6d0z4WLYDqYu0i0x4aL4M4+mZhO
|
||||
fhJNJsERw22EuvGsNycE2B33w41tAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
|
||||
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
|
||||
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
|
||||
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
|
||||
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
|
||||
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
|
||||
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
|
||||
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
|
||||
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
|
||||
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -38,13 +38,13 @@
|
||||
System.Windows.Forms.Label label5;
|
||||
System.Windows.Forms.Label label3;
|
||||
System.Windows.Forms.Label label6;
|
||||
System.Windows.Forms.Label label2;
|
||||
System.Windows.Forms.Label label7;
|
||||
System.Windows.Forms.Label label8;
|
||||
System.Windows.Forms.Label label9;
|
||||
System.Windows.Forms.Label label10;
|
||||
System.Windows.Forms.Label label11;
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(fJobReport_Add));
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.lbSummary = new System.Windows.Forms.Label();
|
||||
this.tbHrs = new System.Windows.Forms.TextBox();
|
||||
this.bs = new System.Windows.Forms.BindingSource(this.components);
|
||||
@@ -93,7 +93,6 @@
|
||||
label5 = new System.Windows.Forms.Label();
|
||||
label3 = new System.Windows.Forms.Label();
|
||||
label6 = new System.Windows.Forms.Label();
|
||||
label2 = new System.Windows.Forms.Label();
|
||||
label7 = new System.Windows.Forms.Label();
|
||||
label8 = new System.Windows.Forms.Label();
|
||||
label9 = new System.Windows.Forms.Label();
|
||||
@@ -204,12 +203,12 @@
|
||||
//
|
||||
// label2
|
||||
//
|
||||
label2.AutoSize = true;
|
||||
label2.Location = new System.Drawing.Point(160, 163);
|
||||
label2.Name = "label2";
|
||||
label2.Size = new System.Drawing.Size(53, 12);
|
||||
label2.TabIndex = 21;
|
||||
label2.Text = "초과시간";
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(160, 163);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(53, 12);
|
||||
this.label2.TabIndex = 21;
|
||||
this.label2.Text = "초과시간";
|
||||
//
|
||||
// label7
|
||||
//
|
||||
@@ -499,7 +498,7 @@
|
||||
this.panel1.Controls.Add(this.tbProject);
|
||||
this.panel1.Controls.Add(projectLabel);
|
||||
this.panel1.Controls.Add(this.tbHrs);
|
||||
this.panel1.Controls.Add(label2);
|
||||
this.panel1.Controls.Add(this.label2);
|
||||
this.panel1.Controls.Add(this.lbTitleTip);
|
||||
this.panel1.Controls.Add(hrsLabel);
|
||||
this.panel1.Controls.Add(this.chkAutoAdd);
|
||||
@@ -671,7 +670,9 @@
|
||||
//
|
||||
// tam
|
||||
//
|
||||
this.tam.AuthTableAdapter = null;
|
||||
this.tam.BackupDataSetBeforeUpdate = false;
|
||||
this.tam.EETGW_DocuFormTableAdapter = null;
|
||||
this.tam.EETGW_JobReport_AutoInputTableAdapter = null;
|
||||
this.tam.EETGW_JobReport_EBoardTableAdapter = null;
|
||||
this.tam.EETGW_NoteTableAdapter = null;
|
||||
@@ -758,5 +759,6 @@
|
||||
private System.Windows.Forms.Button cmbTypeFull;
|
||||
private System.Windows.Forms.ComboBox tbJobGrp;
|
||||
private System.Windows.Forms.ComboBox tbJobType;
|
||||
private System.Windows.Forms.Label label2;
|
||||
}
|
||||
}
|
||||
@@ -352,6 +352,11 @@ namespace FPJ0000.JobReport_
|
||||
|
||||
if (ReadMode)
|
||||
{
|
||||
//개인정보패치 251111
|
||||
label2.Visible = false;
|
||||
tbOt.Visible = false;
|
||||
|
||||
|
||||
panel1.Enabled = false;
|
||||
this.Text += "(읽기전용)";
|
||||
}
|
||||
|
||||
@@ -147,9 +147,6 @@
|
||||
<metadata name="label6.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="label2.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
<metadata name="label7.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</metadata>
|
||||
@@ -175,9 +172,8 @@
|
||||
<value>299, 17</value>
|
||||
</metadata>
|
||||
<data name="richTextBoxEx1.Rtf" xml:space="preserve">
|
||||
<value>{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\froman\fcharset129 \'b8\'bc\'c0\'ba \'b0\'ed\'b5\'f1;}}
|
||||
{\*\generator Riched20 10.0.22621}\viewkind4\uc1
|
||||
\pard\fs20\lang1042 3. \f1\'c7\'c1\'b7\'ce\'c1\'a7\'c6\'ae\f0\lang1033 \f1\'c1\'a6\'b8\'f1\'c0\'ba\f0 (\f1\'b0\'f8\'c0\'e5\'b6\'f3\'c0\'ce\f0 ,PKG\f1\'b0\'f8\'c1\'a4\f0 /\f1\'c0\'e5\'ba\'f1\'b8\'ed\f0 \f1\'c1\'a6\'c1\'b6\'bb\'e7\f0 /\f1\'b8\'f0\'b5\'a8\'b8\'ed\f0 \f1\'c0\'e5\'ba\'f1\'b9\'f8\'c8\'a3\f0 \f1\'c1\'f6\'bf\'f8\'b3\'bb\'bf\'eb\f0 ) \f1\'c7\'fc\'bd\'c4\'c0\'b8\'b7\'ce\f0 \f1\'c0\'db\'bc\'ba\'c7\'d8\f0 \f1\'c1\'d6\'bc\'bc\'bf\'e4\f0 .\lang1042\par
|
||||
<value>{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\froman\fcharset129 \'b8\'bc\'c0\'ba \'b0\'ed\'b5\'f1;}}
|
||||
\viewkind4\uc1\pard\lang1042\fs20 3. \f1\'c7\'c1\'b7\'ce\'c1\'a7\'c6\'ae\lang1033\f0 \f1\'c1\'a6\'b8\'f1\'c0\'ba\f0 (\f1\'b0\'f8\'c0\'e5\'b6\'f3\'c0\'ce\f0 ,PKG\f1\'b0\'f8\'c1\'a4\f0 /\f1\'c0\'e5\'ba\'f1\'b8\'ed\f0 \f1\'c1\'a6\'c1\'b6\'bb\'e7\f0 /\f1\'b8\'f0\'b5\'a8\'b8\'ed\f0 \f1\'c0\'e5\'ba\'f1\'b9\'f8\'c8\'a3\f0 \f1\'c1\'f6\'bf\'f8\'b3\'bb\'bf\'eb\f0 ) \f1\'c7\'fc\'bd\'c4\'c0\'b8\'b7\'ce\f0 \f1\'c0\'db\'bc\'ba\'c7\'d8\f0 \f1\'c1\'d6\'bc\'bc\'bf\'e4\f0 .\lang1042\par
|
||||
}
|
||||
</value>
|
||||
</data>
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace FPJ0000.JobReport_
|
||||
if (tbProcess.SelectedIndex < 0) tbProcess.SelectedIndex = 0;
|
||||
|
||||
this.tbMon.Text = DateTime.Now.Year.ToString();
|
||||
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
if (curLevel < 5) tbProcess.Enabled = false;
|
||||
refrehData();
|
||||
}
|
||||
|
||||
@@ -70,12 +71,13 @@ namespace FPJ0000.JobReport_
|
||||
|
||||
this.dataGridView1.Columns.Add(drYm.yymm, drYm.yymm.Substring(0, 7) + "\r\n(" + basehr.ToString() + ")");
|
||||
}
|
||||
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
//이름으로 정렬해서 데이터를 가져온다
|
||||
var namelist = this.dsReport.jobReport.OrderBy(t => t.uname).GroupBy(t => t.uname);
|
||||
foreach (var uname in namelist)
|
||||
{
|
||||
var drName = uname.FirstOrDefault();
|
||||
if (curLevel < 5 && drName.uid != FCOMMON.info.Login.no) continue; //개인정보 251111
|
||||
|
||||
List<string> rowdata = new List<string>();
|
||||
rowdata.Add(drName.uname + "(" + drName.uid + ")");
|
||||
|
||||
@@ -12,14 +12,14 @@ namespace FPJ0000.JobReport_
|
||||
{
|
||||
public partial class rJobReportDay : fBase
|
||||
{
|
||||
// Boolean binit = false;
|
||||
public rJobReportDay(string baseday )
|
||||
// Boolean binit = false;
|
||||
public rJobReportDay(string baseday)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WindowState = FormWindowState.Maximized;
|
||||
if (baseday.Length > 7)
|
||||
tbMon.Text = baseday.Substring(0, 7);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void rJobReport_Load(object sender, EventArgs e)
|
||||
@@ -35,9 +35,12 @@ namespace FPJ0000.JobReport_
|
||||
this.tbProcess.Text = FCOMMON.info.Login.process;
|
||||
if (tbProcess.SelectedIndex < 0) tbProcess.SelectedIndex = 0;
|
||||
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
if (curLevel < 5) tbProcess.Enabled = false;
|
||||
|
||||
//this.tbMon.Text = DateTime.Now.ToString("yyyy-MM");
|
||||
refrehData();
|
||||
// binit = true;
|
||||
// binit = true;
|
||||
}
|
||||
|
||||
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
@@ -66,15 +69,15 @@ namespace FPJ0000.JobReport_
|
||||
var Process = tbProcess.Text.Trim();
|
||||
if (Process == "%" || tbProcess.SelectedIndex == 0) Process = "";
|
||||
|
||||
var wekklist = new string[] { "일","월","화","수","목","금","토" };
|
||||
var wekklist = new string[] { "일", "월", "화", "수", "목", "금", "토" };
|
||||
|
||||
//날짜에 해당하는 열을 먼저 생성한다
|
||||
dataGridView1.Columns.Add("dvcu_damdang", "사원명");
|
||||
// dataGridView1.Columns.Add("dvcu_process", "공정");
|
||||
var daylist = dsReport.JobReportDay.OrderBy(t=>t.pdate).GroupBy(t => t.pdate);
|
||||
// dataGridView1.Columns.Add("dvcu_process", "공정");
|
||||
var daylist = dsReport.JobReportDay.OrderBy(t => t.pdate).GroupBy(t => t.pdate);
|
||||
foreach (var dayitem in daylist)
|
||||
{
|
||||
|
||||
|
||||
var dtValue = DateTime.Parse(dayitem.Key);
|
||||
var week = wekklist[(int)dtValue.DayOfWeek];
|
||||
this.dataGridView1.Columns.Add("dvcu_pdate", dayitem.Key.Substring(8, 2) + "(" + week.ToString() + ")");
|
||||
@@ -96,26 +99,29 @@ namespace FPJ0000.JobReport_
|
||||
// this.dataGridView1.Columns.Add("dvcu_pdate", dayitem.Key.Substring(8, 2) );
|
||||
//}
|
||||
|
||||
this.dataGridView1.Columns[this.dataGridView1.Columns.Count -1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
this.dataGridView1.Columns[this.dataGridView1.Columns.Count - 1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
}
|
||||
dataGridView1.Columns.Add("dvcu_sum", "합계");
|
||||
this.dataGridView1.Columns[this.dataGridView1.Columns.Count - 1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
|
||||
foreach (var item in dsReport.JobReportDay.Where(t=>t.processs.Contains(Process)).OrderBy(t => t.uname + t.uid).GroupBy(t => t.uname))
|
||||
foreach (var item in dsReport.JobReportDay.Where(t => t.processs.Contains(Process)).OrderBy(t => t.uname + t.uid).GroupBy(t => t.uname))
|
||||
{
|
||||
//사용자별로 데이터를 가져온다.
|
||||
var username = item.Key;
|
||||
var userid = item.FirstOrDefault().uid;
|
||||
if (curLevel < 5 && userid != FCOMMON.info.Login.no) continue;
|
||||
|
||||
List<string> rowdata = new List<string>();
|
||||
rowdata.Add(username);
|
||||
// rowdata.Add(item.FirstOrDefault().processs);
|
||||
// rowdata.Add(item.FirstOrDefault().processs);
|
||||
|
||||
//이 사용자의 데이터를 날짜별로 정렬해서 가져온다.
|
||||
var sum = 0.0;
|
||||
var sumOT = 0.0;
|
||||
var sumFR = 0.0; //휴일근무시간 210310
|
||||
for (int i = 1; i < this.dataGridView1.Columns.Count-1; i++)
|
||||
for (int i = 1; i < this.dataGridView1.Columns.Count - 1; i++)
|
||||
{
|
||||
var col = this.dataGridView1.Columns[i];
|
||||
var dayStr = col.HeaderText.Substring(0, 2);
|
||||
@@ -133,15 +139,15 @@ namespace FPJ0000.JobReport_
|
||||
{
|
||||
//이날은 휴일이다
|
||||
sumFR += daydata.ot;// + daydata.hrs;
|
||||
//sumOT += daydata.ot;
|
||||
rowdata.Add("*" + daydata.hrs.ToString() + "+" + daydata.ot.ToString());
|
||||
//sumOT += daydata.ot;
|
||||
rowdata.Add("*" + daydata.hrs.ToString() + "+" + daydata.ot.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
//평일이다
|
||||
sumOT += daydata.ot;
|
||||
|
||||
if(daydata.jobtype == "휴가")
|
||||
if (daydata.jobtype == "휴가")
|
||||
{
|
||||
if (daydata.hrs + daydata.ot == 8.0) rowdata.Add("휴가");
|
||||
else rowdata.Add((daydata.hrs.ToString() + "+" + daydata.ot.ToString()));
|
||||
@@ -150,7 +156,7 @@ namespace FPJ0000.JobReport_
|
||||
{
|
||||
rowdata.Add((daydata.hrs.ToString() + "+" + daydata.ot.ToString()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else rowdata.Add("--"); //업무일지에 자료가 없다.
|
||||
@@ -158,13 +164,13 @@ namespace FPJ0000.JobReport_
|
||||
rowdata.Add(sum.ToString() + "+" + sumOT.ToString() + "(*" + sumFR.ToString() + ")");
|
||||
this.dataGridView1.Rows.Add(rowdata.ToArray());
|
||||
}
|
||||
foreach(DataGridViewRow dvrow in this.dataGridView1.Rows)
|
||||
foreach (DataGridViewRow dvrow in this.dataGridView1.Rows)
|
||||
{
|
||||
for(int i = 1;i < this.dataGridView1.ColumnCount-1;i++)
|
||||
for (int i = 1; i < this.dataGridView1.ColumnCount - 1; i++)
|
||||
{
|
||||
var col = this.dataGridView1.Columns[i ];
|
||||
var col = this.dataGridView1.Columns[i];
|
||||
var cellvalue = "--";
|
||||
if(dvrow.Cells[i].Value != null) cellvalue= dvrow.Cells[i].Value.ToString();
|
||||
if (dvrow.Cells[i].Value != null) cellvalue = dvrow.Cells[i].Value.ToString();
|
||||
if (cellvalue == "--") dvrow.Cells[i].Style.ForeColor = Color.Gray;
|
||||
else if (cellvalue == "휴가") dvrow.Cells[i].Style.ForeColor = Color.Tomato;
|
||||
else
|
||||
@@ -174,7 +180,7 @@ namespace FPJ0000.JobReport_
|
||||
double ot;
|
||||
if (double.TryParse(datasplbu[1], out ot) == false) ot = 0;
|
||||
|
||||
if(col.Tag.ToString() == "1")
|
||||
if (col.Tag.ToString() == "1")
|
||||
{
|
||||
dvrow.Cells[i].Style.ForeColor = Color.Green;
|
||||
}
|
||||
@@ -198,10 +204,10 @@ namespace FPJ0000.JobReport_
|
||||
dvrow.Cells[i].Style.ForeColor = Color.Red;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
this.dataGridView1.AutoResizeColumns();
|
||||
}
|
||||
@@ -209,11 +215,11 @@ namespace FPJ0000.JobReport_
|
||||
private void tbProcess_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void button1_Click_1(object sender, EventArgs e)
|
||||
private void button1_Click_1(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void lbStt_Click(object sender, EventArgs e)
|
||||
@@ -249,7 +255,7 @@ namespace FPJ0000.JobReport_
|
||||
var sdo = DateTime.Parse(this.tbMon.Text + "-01");
|
||||
var sd = sdo.AddMonths(-1);
|
||||
tbMon.Text = sd.ToString("yyyy-MM");
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void toolStripButton7_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FCOMMON;
|
||||
using AR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -12,10 +13,11 @@ namespace FPJ0000.JobReport_
|
||||
{
|
||||
public partial class rJobReportOT : fBase
|
||||
{
|
||||
int curLevel=0;
|
||||
public rJobReportOT()
|
||||
{
|
||||
InitializeComponent();
|
||||
//this.WindowState = FormWindowState.Maximized;
|
||||
curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.otconfirm));
|
||||
}
|
||||
|
||||
private void rJobReport_Load(object sender, EventArgs e)
|
||||
@@ -38,14 +40,16 @@ namespace FPJ0000.JobReport_
|
||||
|
||||
cmbUserList.SelectedIndex = 0;
|
||||
|
||||
refrehData();
|
||||
//refrehData();
|
||||
}
|
||||
|
||||
void refrehData()
|
||||
{
|
||||
////휴일데이터가 들어가 있음.
|
||||
//var taH = new dsReportTableAdapters.HolidayLIstTableAdapter();
|
||||
//taH.Fill(this.dsReport.HolidayLIst, tbMon.Text + "%");
|
||||
if(curLevel < 5)
|
||||
{
|
||||
UTIL.MsgE("사용 권한이 없습니다");
|
||||
return;
|
||||
}
|
||||
|
||||
var isReqData = cmbApploval.SelectedIndex > 0; //미승인선택
|
||||
string prcname = tbProcess.SelectedIndex < 1 ? "%" : tbProcess.Text.Trim();
|
||||
@@ -459,7 +463,7 @@ namespace FPJ0000.JobReport_
|
||||
|
||||
private void tbProcess_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (tbProcess.SelectedIndex >= 0) refrehData();
|
||||
if (tbProcess.SelectedIndex >= 0 && curLevel >= 5) refrehData();
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -38,6 +38,13 @@ namespace FPJ0000.JobReport_
|
||||
//사용자 목록을 선택한다
|
||||
UpdateUserList();
|
||||
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
if(curLevel < 5)
|
||||
{
|
||||
tbProcess.Enabled = false;
|
||||
cmbUser.Enabled = false;
|
||||
}
|
||||
|
||||
//this.tbMon.Text = DateTime.Now.ToString("yyyy-MM");
|
||||
refrehData();
|
||||
binit = true;
|
||||
|
||||
@@ -45,6 +45,13 @@ namespace FPJ0000.JobReport_
|
||||
//사용자 목록을 선택한다
|
||||
UpdateUserList();
|
||||
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
if(curLevel < 5)
|
||||
{
|
||||
tbProcess.Enabled = false;
|
||||
cmbUser.Enabled = false;
|
||||
}
|
||||
|
||||
refrehData();
|
||||
binit = true;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@ namespace FPJ0000.JobReport_
|
||||
binit = true;
|
||||
|
||||
tbProcess.SelectedIndexChanged += tbProcess_SelectedIndexChanged;
|
||||
var curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport));
|
||||
if(curLevel < 5)
|
||||
{
|
||||
tbProcess.Enabled = false;
|
||||
cmbUser.Enabled = false;
|
||||
}
|
||||
}
|
||||
void UpdateUserList()
|
||||
{
|
||||
|
||||
@@ -97,6 +97,8 @@
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.외출완료ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ta = new FPJ0000.DSKuntaeTableAdapters.EETGW_HolydayRequestTableAdapter();
|
||||
this.cmbUser = new System.Windows.Forms.ToolStripComboBox();
|
||||
this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bn)).BeginInit();
|
||||
this.bn.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bs)).BeginInit();
|
||||
@@ -317,6 +319,8 @@
|
||||
this.dtED,
|
||||
this.toolStripButton7,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripLabel1,
|
||||
this.cmbUser,
|
||||
this.btSearch,
|
||||
this.toolStripButton2,
|
||||
this.toolStripSeparator3,
|
||||
@@ -681,6 +685,18 @@
|
||||
//
|
||||
this.ta.ClearBeforeFill = true;
|
||||
//
|
||||
// cmbUser
|
||||
//
|
||||
this.cmbUser.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbUser.Name = "cmbUser";
|
||||
this.cmbUser.Size = new System.Drawing.Size(150, 37);
|
||||
//
|
||||
// toolStripLabel1
|
||||
//
|
||||
this.toolStripLabel1.Name = "toolStripLabel1";
|
||||
this.toolStripLabel1.Size = new System.Drawing.Size(43, 34);
|
||||
this.toolStripLabel1.Text = "담당자";
|
||||
//
|
||||
// fHolyRequest
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
@@ -771,5 +787,7 @@
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn Response;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn HolyBackup;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn remarkDataGridViewTextBoxColumn;
|
||||
private System.Windows.Forms.ToolStripLabel toolStripLabel1;
|
||||
private System.Windows.Forms.ToolStripComboBox cmbUser;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,8 @@ namespace FPJ0000
|
||||
cmbCf.DisplayMember = "DP";
|
||||
cmbCf.ValueMember = "VAL";
|
||||
dv1.EditMode = DataGridViewEditMode.EditProgrammatically;
|
||||
curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.holyreq));
|
||||
|
||||
}
|
||||
|
||||
void __Closed(object sender, FormClosedEventArgs e)
|
||||
@@ -48,19 +50,71 @@ namespace FPJ0000
|
||||
private void __Load(object sender, EventArgs e)
|
||||
{
|
||||
EnsureVisibleAndUsableSize();
|
||||
curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.holyreq));
|
||||
|
||||
this.dtED.Text = DateTime.Now.AddMonths(1).ToShortDateString();// sdate.AddMonths(1).AddDays(-1).ToShortDateString();
|
||||
this.dtSD.Text = DateTime.Now.AddMonths(-1).ToShortDateString();
|
||||
|
||||
this.dv1.EditMode = DataGridViewEditMode.EditProgrammatically;
|
||||
UpdateUserList();
|
||||
|
||||
btSave.Visible = false;// curLevel >= 5;
|
||||
btEdit.Text = curLevel >= 5 ? "승인(&E)" : "편집(&E)";
|
||||
// binit = true;
|
||||
|
||||
if (curLevel < 5)
|
||||
{
|
||||
cmbUser.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cmbUser.Items.Count > 0)
|
||||
cmbUser.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
refreshData();
|
||||
}
|
||||
|
||||
void UpdateUserList(bool datelist = false)
|
||||
{ //this.cmbUser.DisplayMember = "dispName";
|
||||
//this.cmbUser.ValueMember = "id";
|
||||
// this.bs.DataSource = dr;
|
||||
this.cmbUser.Items.Clear();
|
||||
this.cmbUser.Items.Add("-- ALL --");
|
||||
//해당그룹내의 사용자 목록을 가져와야한다
|
||||
if (datelist == false)
|
||||
{
|
||||
var dtUser = FCOMMON.DBM.getActiveUserTable();
|
||||
foreach (DataRow dr in dtUser.Rows)
|
||||
{
|
||||
this.cmbUser.Items.Add(dr["dispname"].ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var ta = new dsQueryTableAdapters.HolydayUserListTableAdapter();
|
||||
var dtUser = ta.GetData(FCOMMON.info.Login.gcode, dtSD.Text, dtED.Text);
|
||||
foreach (dsQuery.HolydayUserListRow dr in dtUser.Rows)
|
||||
{
|
||||
this.cmbUser.Items.Add($"{dr.UserName}({dr.uid})");
|
||||
}
|
||||
}
|
||||
this.cmbUser.Text = $"{FCOMMON.info.Login.nameK}({FCOMMON.info.Login.no})";
|
||||
//if (this.cmbUser.SelectedIndex < 0) this.cmbUser.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
string GetUIDValue()
|
||||
{
|
||||
string uid = "%";
|
||||
if (cmbUser.SelectedIndex > 0)
|
||||
{
|
||||
var si = cmbUser.Text.IndexOf("(");
|
||||
var ei = cmbUser.Text.LastIndexOf(")");
|
||||
uid = cmbUser.Text.Substring(si + 1, ei - si - 1);
|
||||
}
|
||||
return uid;
|
||||
}
|
||||
|
||||
private bool getKisulInput
|
||||
{
|
||||
@@ -112,7 +166,13 @@ namespace FPJ0000
|
||||
//dsMSSQL.JobReport.Clear();
|
||||
var sd = dtSD.Text.Trim();
|
||||
var ed = dtED.Text.Trim();
|
||||
ta.Fill(this.dSKuntae.EETGW_HolydayRequest, FCOMMON.info.Login.gcode, sd, ed);
|
||||
var seluid = GetUIDValue();
|
||||
|
||||
var uid = "";
|
||||
if (cmbUser.SelectedIndex == 0) uid = "%";
|
||||
else uid = GetUIDValue();
|
||||
|
||||
ta.Fill(this.dSKuntae.EETGW_HolydayRequest, FCOMMON.info.Login.gcode, sd, ed, uid);
|
||||
|
||||
var sum_day = dSKuntae.EETGW_HolydayRequest.AsEnumerable().Where(t => t.conf == 1).Sum(t => t.HolyDays);
|
||||
var sum_time = dSKuntae.EETGW_HolydayRequest.AsEnumerable().Where(t => t.conf == 1).Sum(t => t.HolyTimes);
|
||||
@@ -174,7 +234,7 @@ namespace FPJ0000
|
||||
else
|
||||
{
|
||||
search = search.Replace("'", "''");
|
||||
var collist = new string[] {"name", "Response", "HolyReason","remark" };
|
||||
var collist = new string[] { "name", "Response", "HolyReason", "remark" };
|
||||
string filter = ""; // "itemna like ? or package like ? or projectname like ? or process like ? or [type] like ? or description like ?";
|
||||
foreach (var col in collist)
|
||||
{
|
||||
@@ -334,11 +394,11 @@ namespace FPJ0000
|
||||
}
|
||||
}
|
||||
|
||||
if(FCOMMON.DBM.GetMagamStatus(dr.sdate.Substring(0,7)))
|
||||
{
|
||||
if (FCOMMON.DBM.GetMagamStatus(dr.sdate.Substring(0, 7)))
|
||||
{
|
||||
FCOMMON.Util.MsgE("마감된 자료이므로 삭제할 수 없습니다");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (FCOMMON.DBM.GetMagamStatus(dr.edate.Substring(0, 7)))
|
||||
{
|
||||
@@ -381,18 +441,18 @@ namespace FPJ0000
|
||||
var drv = this.bs.Current as DataRowView;
|
||||
if (drv == null) return;
|
||||
var dr = drv.Row as DSKuntae.EETGW_HolydayRequestRow;
|
||||
if(dr.cate.Equals("외출")==false)
|
||||
if (dr.cate.Equals("외출") == false)
|
||||
{
|
||||
FCOMMON.Util.MsgE("외출 자료만 완료할 수 있습니다");
|
||||
return;
|
||||
}
|
||||
if(dr.conf != 1)
|
||||
if (dr.conf != 1)
|
||||
{
|
||||
FCOMMON.Util.MsgE("관리자 승인된 자료만 완료할 수 있습니다");
|
||||
return;
|
||||
}
|
||||
var f = new OtConfirm.fOutCoomplete(dr);
|
||||
if(f.ShowDialog() == DialogResult.OK)
|
||||
if (f.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
dr.stime = f.dtSD.Value.ToString("HH:mm");
|
||||
dr.etime = f.dtED.Value.ToString("HH:mm");
|
||||
|
||||
@@ -130,78 +130,78 @@
|
||||
<data name="bindingNavigatorMoveFirstItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wQAADsEBuJFr7QAAASpJREFUOE9jGDygcNbz/00Lnv/PnPj4P1QIA4S3P8Apx5A789n/VUfe/8elKL77
|
||||
wf/ghmu4DciY8vT/wn0fsCqK73n4f+n+///9qy/gNiCh58n/aVveYyiKaL8P1pw56/9/r9ITuA2I7Hr0
|
||||
v3f1BxRFoa33wJpb1wFt7/z73yX/AG4DApsf/q+b/w6uKLjl7v9Fe///7wBqzpjz879d3c//9hnbcRvg
|
||||
UXX/f/60NyiK7Ipv/0+f8/u/f9e3/zqF7/5bJKzHbYB96d3/2ZNfYyjSTzn/36ToxX+VrE//jSOX4TbA
|
||||
Iu/O/9T+11gVGSSd+C+b9vW/bvA83AYYZt3+H9byEqci/dTL/zV8p+E2QCftxn+/6od4Fal4TMBtgFPu
|
||||
lf8gBXgVDULAwAAA8HbAq6XlmnAAAAAASUVORK5CYII=
|
||||
wQAADsEBuJFr7QAAATFJREFUOE9jYBg0oHDW8/9NC57/z5z4+D+6HAyEtz/AKceQO/PZ/1VH3v/HpSi+
|
||||
+8H/4IZrWOXAIGPK0/8L933Aqii+5+H/pfv///evvoAhBwcJPU/+T9vyHkNRRPt9sObMWf//e5WewG1A
|
||||
ZNej/72rP6AoCm29B9bcuu7/f//Ov/9d8g/gNiCw+eH/uvnv4IqCW+7+X7T3//+Odf//Z8z5+d+u7ud/
|
||||
+4ztuA3wqLr/P3/aGxRFdsW3/6fP+f3fv+vbf53Cd/8tEtbjNsC+9O7/7MmvMRTpp5z/b1L04r9K1qf/
|
||||
xpHLcBtgkXfnf2r/a6yKDJJO/JdN+/pfN3gehhwcGGbd/h/W8hKnIv3Uy/81fKdhlQMDnbQb//2qH+JV
|
||||
pOIxAaccg1Pulf8gBXgVDUoAAPB2wKtYlLYeAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="bindingNavigatorMovePreviousItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wQAADsEBuJFr7QAAALZJREFUOE9jGDogvP3BfyiTdBDf/eB/cMM18gyI73n4f+n+///9qy+QbkBE+32w
|
||||
5sxZ//97lZ4gzYDQ1ntgza3rgLZ3/v3vkn+AeAOCW+7+X7T3//8OoOaMOT//29X9/G+fsZ00F9gV3/6f
|
||||
Puf3f/+ub/91Ct/9t0hYT3oY6Kec/29S9OK/Stan/8aRy0g3AAQMkk78l037+l83eB55BoCAfurl/xq+
|
||||
08g3AARUPCZQZsBgBQwMANAUYJgEulBVAAAAAElFTkSuQmCC
|
||||
wQAADsEBuJFr7QAAALtJREFUOE9jYBgyILz9wX90MaJBfPeD/8EN18gzIL7n4f+l+///96++QLoBEe33
|
||||
wZozZ/3/71V6gjQDQlvvgTW3rvv/37/z73+X/APEGxDccvf/or3//3es+/8/Y87P/3Z1P//bZ2wn3gAQ
|
||||
sCu+/T99zu///l3f/usUvvtvkbCeNANAQD/l/H+Tohf/VbI+/TeOXEa6ASBgkHTiv2za1/+6wfPIMwAE
|
||||
9FMv/9fwnUa+ASCg4jGBMgMGLwAA0BRgmCws/7cAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="bindingNavigatorMoveNextItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wQAADsEBuJFr7QAAAKNJREFUOE9jGHygcNbz/1AmeSB35rP/Cd33yDckY8rT//P2//6f0HWHPEMSep78
|
||||
n73v1//OrX//u5VeJt2QyK5H/6ds+/W/ZOnf/wnT//63yT1LmiGBzQ//t659D9ZsXPLlv3T0tf/GkcuI
|
||||
N8Sj6v7/krnv4JoVXXpIc4F96d3/gS3PyNMMAhZ5d/7bFFwhTzMIGGbdJl8zCOik3SBf81AEDAwAoH5f
|
||||
oAc0QjgAAAAASUVORK5CYII=
|
||||
wQAADsEBuJFr7QAAAKRJREFUOE9jYBh0oHDW8//oYiSB3JnP/id03yPfkIwpT//P2//7f0LXHfIMSeh5
|
||||
8n/2vl//O7f+/e9Wepl0QyK7Hv2fsu3X/5Klf/8nTP/73yb3LGmGBDY//N+69j1Ys3HJl//S0df+G0cu
|
||||
I94Qj6r7/0vmvoNrVnTpIV4zCNiX3v0f2PKMPM0gYJF3579NwRXyNIOAYdZt8jWDgE7aDfI1D00AAKB+
|
||||
X6Bjq5qXAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="bindingNavigatorMoveLastItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
|
||||
wQAADsEBuJFr7QAAASxJREFUOE9jGFygcNbz/1AmBgDJNS14/j9z4mOcahhyZz77n9B9D6sCkNyqI+//
|
||||
h7c/wG1AxpSn/+ft//0/oesOhiKQ3MJ9H/4HN1zDbUBCz5P/s/f9+t+59e9/t9LLKApBctO2vP/vX30B
|
||||
twGRXY/+T9n263/J0r//E6b//W+TexauGCTXu/rDf6/SE7gNCGx++L917XuwZuOSL/+lo6/9N45cBtYA
|
||||
kqub/+6/S/4B3AZ4VN3/XzL3HVyzoksPXDFILn/am//2GdtxG2Bfevd/YMszDM0gAJLLnvz6v0XCetwG
|
||||
WOTd+W9TcAVDMwiA5FL7X8O9hBUYZt3GqhkEQHJhLS//6wbPw22ATtoNnJIgOb/qh/81fKfhNgAfcMq9
|
||||
8l/FYwIYQ4UGBWBgAAC+0b+zuQxOnAAAAABJRU5ErkJggg==
|
||||
wQAADsEBuJFr7QAAAStJREFUOE9jYBhUoHDW8//oYjAAkmta8Px/5sTHONUw5M589j+h+x5WBSC5VUfe
|
||||
/w9vf4BVHgwypjz9P2//7/8JXXcwFIHkFu778D+44RqGHBwk9Dz5P3vfr/+dW//+dyu9jKIQJDdty/v/
|
||||
/tUXcBsQ2fXo/5Rtv/6XLP37P2H63/82uWfhikFyvas//PcqPYHbgMDmh/9b174HazYu+fJfOvraf+PI
|
||||
ZWANILm6+e/+u+QfwG2AR9X9/yVz38E1K7r0wBWD5PKnvflvn7EdtwH2pXf/B7Y8w9AMk8ue/Pq/RcJ6
|
||||
3AZY5N35b1NwBUMzTC61/zXcS1iBYdZtrJpBACQX1vLyv27wPKzyYKCTdgOnJEjOr/rhfw3faTjV4AVO
|
||||
uVf+q3hMAGN0uYEFAL7Rv7NmXVYYAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btFind.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE3SURBVDhPnZIxS8NQFEb7W/wLjh0Fl9a1SxBHBekkWFd1
|
||||
qYg4Ci5dndSCg2AHl4LQSaRSKDqoFUE7VAjUmvTKueWmL2mw2gunL7zmO+/mJhmZoTJusdF868vpXUfO
|
||||
b5/lpPEox9f3SvnsRtk8uojxHQ7HEgSEkXS6vrz3xqtdu+xdfUiheEBsJOGCk/mz/hROUHsIIrp+qIKY
|
||||
hB/a9r+CVAG4Auj5g7iA5/1NACaptgIVLHkb0wWVw13ZL60p2+uerqkCJs1mMgwUU6d1k/xJwI10RZj1
|
||||
9TPUN7Wam9dgTMC75QR7TjCBkRQs5Jd1jQS8c1ewtZLTPcQW/peADpC44cudgnjZOQ1OCGjTwkwaGBon
|
||||
GoSrpcVIQqmAj6LZftFBup9vWiUlUQdIDCbsQrsGZRJKBbOXyA++SlEsu6QjvQAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEwSURBVDhPpZIxSwNBEIXzW/wLKS0Fm2ib5hBLBbESjG20
|
||||
UUQsBRtbKzVgIWhhIwhWIhFBtFAjgqaIcKDmLiPfwO7NXg6NZuDdLnv3vn03uyX5R5VssdB8+ZC9q5Yc
|
||||
XD7K7sW9bJ9eq1b3z1WLW4eBumkvgwDADKTVjuW1k41ubrV2/CbV+Y0sCRN25uXZQ9qnk7vEqx2nCggg
|
||||
PIgdfyZ95jwEAOrEXyGA//0JYCGNm0QBk9HC74CdzRVZr82q6nORjoUAOs1i3owouk50BxkIwIekwsz4
|
||||
/J7qSc1UymoMAJwtO9iOO4BTHjA2MRUCOHMLWJqu6BpgZ/4TgARArPlouSrR6EgxgJj2qBBNY0cnzI3a
|
||||
uId4AJeiefukjbTXt6jyEJ8AiBMdtiKuk4V4wDD1Db5KUSxr13uqAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="btSave.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE1SURBVDhPY/hPIQAbcOn57//T915BwW1rjoFx/oJz//N6
|
||||
VqHgsNxeMA03YN3lp/9vv4YYhAtsuQ6h55/9A8aBidVgPtiADZcegzWDFN1/9///qy8IDOKDcPfu1/9/
|
||||
/vn/v3rt/f9TD38BuwJuwIrT9wka0L79BdiAkuW3MA0A+fnog///V12GKAZ5BxcGGQByDYoXYAbA/Aey
|
||||
AYRBCkE2N256AnY6SDMoUEF8FANAoQ0zAFkzCCNrhhkAor3CczENwGYzuu1JM8+BaQwDQAGITzOyASDs
|
||||
4huPMAAkATIA3c/YNIdNPAHGKAaAUhUoBghphhng0rTnv71bGKoBoADE5mR0zVgNACUK9BgAGYbudJBG
|
||||
GNY0dEYYAMsgMAyKYxAGhTQIg/wLwiBbQRikGSUdkA/+/wcAgXJEf04PwQkAAAAASUVORK5CYII=
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEzSURBVDhPY/hPIWAAEZee//4/fe8VFNy25hgY5y849z+v
|
||||
ZxUKDsvtBdNwA9Zdfvr/9muIQbjAlusQev7ZP2AcmFgN5oMN2HDpMVgzSNH9d///v/qCwCA+CHfvfv3/
|
||||
55///6vX3v8/9fAXsCvgBqw4fZ+gAe3bX4ANKFl+C9MAkJ+PPvj/f9VliGKQd3BhkAEg16B4AWYAzH8g
|
||||
G0AYpBBkc+OmJ2CngzSDAhXERzEAFNowA5A1gzCyZpgBINorPBfTAGw2o9ueNPMcmMYwABSA+DQjGwDC
|
||||
Lr7xCANAEiAD0P2MTXPYxBNgjGIAKFWBYoCQZpgBLk17/tu7haEaAApAbE5G14zVAFCiQI8BkGHoTgdp
|
||||
hGFNQ2dUF4AMgWFQHIMwKKRBGORfEAbZCsIgzSjpgBIAAIFyRH86fUztAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
|
||||
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
|
||||
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
|
||||
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
|
||||
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
|
||||
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
|
||||
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
|
||||
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
|
||||
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
|
||||
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIFSURBVDhPpZLtS1NhGMbPPxJmmlYSgqHiKzGU1EDxg4iK
|
||||
YKyG2WBogqMYJQOtCEVRFBGdTBCJfRnkS4VaaWNT5sqx1BUxRXxDHYxAJLvkusEeBaPAB+5z4Jzn+t3X
|
||||
/aLhnEfjo8m+dCoa+7/C3O2Hqe0zDC+8KG+cRZHZhdzaaWTVTCLDMIY0vfM04Nfh77/G/sEhwpEDbO3t
|
||||
I7TxE8urEVy99fT/AL5gWDLrTB/hnF4XsW0khCu5ln8DmJliT2AXrcNBsU1gj/MH4nMeKwBrPktM28xM
|
||||
cX79DFKrHHD5d9D26hvicx4pABt2lpg10zYzU0zr7+e3xXGcrkEB2O2TNec9nJFwB3alZn5jZorfeDZh
|
||||
6Q3g8s06BeCoKF4MRURoH1+BY2oNCbeb0TIclIYxOhzf8frTOuo7FxCbbVIAzpni0iceEc8vhzEwGkJD
|
||||
lx83ymxifejdKjRNk/8PWnyIyTQqAJek0jqHwfEVscu31baIu8+90sTE4nY025dQ2/5FIPpnXlzKuK8A
|
||||
HBUzHot52djqQ6HZhfR7IwK4mKpHtvEDMqvfCiQ6zaAAXM8x94aIWTNrLLG4kVUzgaTSPlzLtyJOZxbb
|
||||
1wtfyg4Q+AfA3aZlButjSfxGcUJBk4g5tuP3haQKRKXcUQDOmbvNTpPOJeFFjordZmbWTNvMTHFUcpUC
|
||||
nOccAdABIDXXE1nzAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
@@ -210,62 +210,62 @@
|
||||
<data name="toolStripButton8.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANPSURBVFhH7dhZTxNRHAVwPoRx3yuyKWUvqyJu4BqNiYnx
|
||||
C/giaowRQSiibC0Uyg6CyqKSuEaEQvdCK7tPqAmokWDUiFGgyCrHO+k0oT609w4JvvQk9/n+MjPn/ifX
|
||||
wx133BGQh8dfX3hwzGy9f7QfDUfIOtyH+kN9qEvoRW18L+4d7MHdAz24s5+sfd2o2duN6rgu3N7TharY
|
||||
TlTu7kTFrlcojyEr2oKyKAtKIy0oiTCjONyMIkkHlGFkhbajMKQdBcEma36QIZHf3nWWGQdFkAm5gaYJ
|
||||
fnvXWW5cfqAJeQFG8Nu7zv/AycUswCXgyqLNUEbokSdpQ4FEh6LwDiqc3N9AD1zKkyuM1KL/8UfMTs2j
|
||||
p/ED5CEaKpxsJwNQKI57cu2V77A4xfFaKlzuDj09UAiuONKER5e6sfBngacBP0cmIQtTUeFy/BiArLjS
|
||||
qA5UnTJgemKWpwFzM/OoOWuEIthIhcv21dED2XCkFLFafH8/ztNseSHtR16wjhqX5cMApMVxR4kiXIO3
|
||||
ms88y5auhiFy8KqZcJneLEBKXGG4HqYKx1IM94+S766VGZfppaUH0uCKIkgpLjqWYuzLbxTGqcl3Z2DG
|
||||
3drOAHSFK4nkS2Gd42m2UlSfMYIMfUG4m54aeqAzHDe+FGE6DHV85Wm2PEvpgzxIKxiXsY0B6AzHzdb8
|
||||
UB0G2x2BT5N7IQvUCsbdEKnpgc5w3OBXSkwoP6F3fMXT86g8TUBivSBc+lYGoDOcffArQvRoTOxyKMkv
|
||||
UhJ5TCtk/jpmnHRLGz3QFc4+W2VBGuhL3/A8Wz71jSJT3MyMS9vMAqTA2c+5LLEKA20jPM8WS+0gMnxb
|
||||
mHBpm1rpgbQ4rhDyAANyJCp8GxrjebY8SepBhncrNS51IwOQFmdvK/fNKRM0mBpf9LNASlN6kqC81FS4
|
||||
6xsYgCw4e1uz/NSoP2d2KM2P4QlIfZqocCnrVfRAVpy9EBk+KmiUAzzPluyIFipc8joGoBCcvRBS75fo
|
||||
JH8zM5NzsNQNIlXURIW7traFHigUZy+E1LMFKaLnBNeMdFEbFS5pDQtwCTjaQvyLS1rdTA/8H7irqxiA
|
||||
BGddbtzllU30Vx/cRQ53V7KcuCsrms7z27vjjjv08fD4CwlIPe+HvHrCAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANNSURBVFhH7dhnT1NRHAZwPoRx74osZZTRUkARFzijMTEx
|
||||
fgHfiBpjRBCKIKuFQtkgoEBVElwRoaWTLkahvkJNQI0Eg0aMsqc85ia24TYBzrkk+KbPJ/jl3Puc/8nf
|
||||
w8Mdd9yhz9Ozb689OWMZf3zaDsUpOxQne1B/ogd1cd2oje3Go+M2PDxmQ81RG2qOdKH6cBeqYjrx4FAn
|
||||
KqM7UHGwA+UH2lEW1Y6ySCtKI6woEVlRHG5BkdCCQoEZ8jAz5KEmFISYkB9sHM/jG+JdHUtmjXGQ8Y3I
|
||||
CTKOuTqWzFrj8oKMyA1sg6tjyfwPnDSABrgKXGmkBfJwPXIFrcgX6FAoNBPhpP4GciBXHHNyBSIt7M8+
|
||||
Y3ZqHraGT5CGaIhwkv0UQK445uRMFR+wOEWxWiJczj49OZALrkhkROONLiz8WXDifg1OQBKmJMJl+1EA
|
||||
aXElEWZUXjBgemzWiZubmUf15TbIgtuIcFm+OnIgHc4CebQWPz6OOnFMXovtyA3WEeMyfSiApDjmKpEJ
|
||||
NXiv+crCdSr6kROkpsJleNMACXEFQj2M5exSDNiHIQlTUeMyvLTkQBJcYbgRjdfZpRgZmkRBjBqyYAM1
|
||||
7v5eCuBKuGLRv1KMzzlxTCmqLrUhj88Nl+6pIQcuh2PGlyxMh37zNyeOycukHkj5Ws64tD0UwOVwzGzN
|
||||
C9Whz8QGvkjshiRIyxl3j6cmBy6HYwa/XGBE2Tk9+xNPz6PiogGSAD0nXOpuCuByOMfgl4Xo0RDfySrJ
|
||||
76FJSKNUkPjrqHHiXa3kwJVwjtkq4WugL3nnBDL50jOMjIBmalzKThogAc5xz2UGKNHbOshCWmv7kObb
|
||||
QoVL2aEiB5LimEJIAw3IFijxvX+EhXyeYEOat4oYl7ydAkiKc7SV+efkcRpMjS56LEzPo+S8FuleaiLc
|
||||
3W0UQBqco62ZfmrUX7GwSvNzYAxinyYiXNJWJTmQFucoRJqPEhp5rxPIJCu8hQiXuIUCyAXnKITY+w06
|
||||
FP2YmZiDta4PybwmItydzS3kQK44RyHEni1I4r1CMq8ZqbxWIlzCJhrgKnCkhXDFJWxsJgf+D9ztDRRA
|
||||
Zley1rib65vIVx/MIofZlawl7ta6pquuDnfccYcgfwEJSD3vAJhh2AAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton7.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANSSURBVFhH7djZTxNRGAVw/gjjvq9tVWgBAbUguO+aGE18
|
||||
8N0XFROj4oYitHbB0haL4i4qGhUTRew27bS1pRSEJ4kkKCZuiRhJpEQE5TjDTKPEpL13TPClJ7nP95e5
|
||||
c+a7mZRkkklGQu5saSus3RyM3t7UilsbubXhOW6uf46adS24sbYF19c049rqZlxdxa2VEVxZEcHl5U24
|
||||
VNCEi/lhVC8L40JeI87ncksdQtXSEGxLQji3OIjKnCCs2c9gyeLWogDMmQFUZPijZ9PZfeL2iTPKOJjS
|
||||
/dCr/L3i9okz2rizKj/KlT6I2yfO/8AZ02iAhLiLBWHY8nwwq12oVLOoyg1JxhlTWXIg6ZOrzGXRer8L
|
||||
A99+oK3uDSxLGck4w0IKIPGxbmXxZwLVL2HO8UrC6Rd4yYGk75w1n0HP+z6RBwz9HMK9/RGYs33UON18
|
||||
CiBpIWzqIK7vCgwfcSzfo4Oo3s7CnOWnwp1ReMiBJLhYW61LfHh0vFXkCfn8phemPCcqMv3EOK2cAkiK
|
||||
ixXClOVBpPaVyBPSwX6EPt1BjNPIaIAUuFghjNkOdEW6RZ4Qr60dOqWbCKeZx5ADaXF8IcxZ3LuW70TP
|
||||
uz9KMwTcLQzjTKo7Ia5sLgWQFhdrqynDh0s7WQz2/y5Nf+8ArBvc0C/0xMWVznGTA6XgYm01qBg8PNIi
|
||||
8oR0+D6iVGGPizs9mwIoFccXQq9kUFc0EvjS+4EDOuLiSma5yIFScUYliws7vH8dsXmdC1oFExd3aiYF
|
||||
UAquXOWDQW3Hl7dRkSaUpHZPI0rljoS4kzOc5EBaHP+d0ygb8DrySaQJYSwvcFpuJ8IVT6cBUuK0qU40
|
||||
3uwUWULamfcoUTwhxhVPc5ADaXC6NDceHGoWWUK6X3+FJrMBGjlDjDsxlQJIijOkeVG1zTvistDPXRYs
|
||||
613UuONTKIAkOH58aVVPR5aCu27V7A6iVOakxh2bbCcHkuD42WoqcIo0IXwpSmR2SbijkyiAJDh+tpbN
|
||||
t6Ppdie+9w0ifKsTp+RPJOOOTHxKDiTB8YNft8AzPCFOyh7/05PjcUUTaIAEuESDnxZXNL6BHPg/cIfH
|
||||
UQA5XHS0cQfG1pP/+uB/5PD/SkYTd3BM/V5x+2SSSYY8KSm/AHvBPpKbf2MsAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANRSURBVFhH7dhZT5NBGAVgfoRx31daWVpAUCgI7uCaGE28
|
||||
8N4bFROjgqKApaVspQXZXZBNo2LiAm3pR7+2tpSW5UqCCQKJookYSaRGFOGYIWm1GGDmM4Gbnl/wZCZn
|
||||
3skbEOCPP/6w58HR7uSGIzZ3/eEu1B3qQt3BTtQmdaImsQP3D3Sger8L9/a5cHevC3f3OHFntxO3d7Wj
|
||||
KqEdlfEOVOx0oDyuDWWxbSiT2VEaY0dJtB23dthQvN2GoqhX0Ea+gnabFZoIKwrDLe6CMP78dMeMmWcc
|
||||
1GEW5Egto9MdM2a+cQVSC/IlZkx3zJiFwOWFsgApcZUJDpTEmaGRtaBYxqM01i4YlxfC0wNpcOTkimN5
|
||||
dD0ewM/vv9DdOAhtDCcYlxvMAKTBTV3rMR5/x1rRC812kyBcTpCJHkiF2+lAUTyHkaFvXuDkxCQeXXBC
|
||||
E2Vmxqm2MgBpcKQQJTIbqk9bp67Ykx/ucVSc4KGJtDDhssWt9EAanKetRdFmPEvr8gJJPg+OQh1nQGGE
|
||||
hRqnFDEAaXGeQqgjW+FseOuDfMN/RE6YnhqnCGQBMuA8hciL0mPAOeyDNJX0QCUxUuEUWzh6ICuOFEIT
|
||||
aUVhvAEj7/8qzSTwMNmB7BDjnLiszQxAVpynrepwM6pO8Rgf+1OasdGfKDpoRE5w66w4+SYjPVAIztPW
|
||||
XCmHp6kdXiDJG/NHyMW6WXE3NzIAheKmfiUSDo0pvsBe0wfIxfpZcZkbWuiBQnF5Eh7lJ03/XLEmsQVK
|
||||
MTcrLmM9A1AILl9qRq5Mhy/v3F4cKUnD2TbIRfo5cenrDPRAVhx55xSSJvQ7P3lxJJz2NW6KdFS4G2tZ
|
||||
gIw4ZYgBbbV9PrgebgiZ4pfUuBtr9PRAFpwq1Ignl10+uOH+r1BENEEh4qhx11czAGlxuaEmlB43+XwW
|
||||
xtzj0Ca1MOPSVjEAaXBkfCmlzb6lmJhEzRkb5IEGZty1lTp6IA2OzFZ1gsGLIyGlyAzUCcJdXcEApMGR
|
||||
2Zq1VYf2+j78+DYOR10fMkQvBeNSlzfTA2lwZPCrglqnJkR64PP/OjmCS1nGAqTAzTX4WXEpS5vogQuB
|
||||
u7KEAUh2JfONu7j4Bf3qgyxyyK5kPnGXFr04N93hjz/+UOQ3e8E+krxr0cIAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
<data name="btSearch.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE4SURBVDhPtZPPasJAEMbzPn0FwWA92JtP4NGKB1/DP7ei
|
||||
QSsovkChh7ZBrCfpyR4sikopUgq9StFzM/UbZ5asSS4FfzAkO7vft5udiZMEnSBpk5dhFJmncjdHxXaG
|
||||
A+9K4SbFT1luEwQBbXavVO5d0nI3ovnW5yeiMriiu+kt5asXbABEdgRigAUQDr+aHLU3lxoLl/yPJhvF
|
||||
GsiYJ/vPdX5qPK3bVJ25VFukafztGQNsKHJ791I3w+8KcpNth8XDz5YxACI/gsR1J8sTYcO4UIzwv1gG
|
||||
cTshgJ5IT8hChTMHsHi+v+fvffmxywVwN2FDkdsGEOK2ceu4feQ0tDqKyKMGqDfqjvprLzyswuX7Tf4E
|
||||
dBo6zn/3OB7XHovRyuhQ6+hhYKA9DpL+A1keRebNAhkaJH0OHOcP031C4EjYr6wAAAAASUVORK5CYII=
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEiSURBVDhPY2DAAf6jAXRxVNVIAKYga5bH/7TpTmAMYsNA
|
||||
3EQb3Ab8+/fv/71PZ/5nzXX+f+3T7v+X320H0yCct8Dz/9rTM/8HtGvDDcPQDAIgBSCNOx9NBuOOiw7/
|
||||
u644/N9+ZzLYIKwGwARAkvP2dIJpGN52Y/r/9gsO/zuu2P/f+3Qq3ACQhVhtz5jlBLcBJnb43Qyw5p0P
|
||||
pmB3AcwV6TNcwBLIBmLDKAbAeWQAFAPQbUG2DeYimAsxnA4z4PLnDWD/Hv2AGl0gAAobZAOxGgDSCApt
|
||||
UKiDQh/ZJbDYgQGcBoDiGxTvoPiHpYUt15Gj7y9uL4BSGijFbb81FYy33pgK1gxKyqAUiuJ0ZAAyAJbG
|
||||
QQBXPkDXBwfoCuA60MRpAgDTfULg/+7qPQAAAABJRU5ErkJggg==
|
||||
</value>
|
||||
</data>
|
||||
<data name="toolStripButton2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADlSURBVEhL7dQxCsIwFMbxnMrZWatzUXRUCo5ewSs4ewZR
|
||||
DyDeQfEETsUbRL7YYNSXNC/UOiQP/kvzyE9KUcQ7y/VJtlHFvQYPjzf50xKsJsFmq81WHq538swMO9il
|
||||
zhALxkWd7kAOJwsnjjPsYNeGs2B14fR5YTYq5O5c1u7sL987iAUjF+6LIjaMKJyDoiAYmVAvn8lsXHij
|
||||
KBhGwDWof4APihqHqQ+OKhg2X3U/n7+9ah88CKY+pM9ndTgbplDbmQtnwS7UtmPDWfDf/jIRLnKhOuzY
|
||||
UMSGmyrBauKE26jiohshHicE2B3dbRrmAAAAAElFTkSuQmCC
|
||||
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADiSURBVEhL7dVBCsIwEAXQnsq1a62ui6JLpeDSK3gF155B
|
||||
1AOId1A8gSvxBiNTCcTJJM3E2i6SwN9MhnklDW2WRbvW2wu0EepW8PkBf02CE2xks9vD6f4y6jTYg720
|
||||
riKCcVCvP4LxbOXEcQ97sNeGi+Bq4PwzMJ+UcLg+a3uON7NHDHODdZzu2dAgmAMQpzUXGgxTfFAsIJ+W
|
||||
3uhPMAZxBaoH8EExjcPcheMSDOtHPSyWX0ftgwfB3EWitTpcDFNAf6d0z4WLYDqYu0i0x4aL4M4+mZhO
|
||||
fhJNJsERw22EuvGsNycE2B33w41tAAAAAElFTkSuQmCC
|
||||
</value>
|
||||
</data>
|
||||
<metadata name="HolyDays.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
|
||||
@@ -96,7 +96,12 @@ namespace FPJ0000
|
||||
}
|
||||
|
||||
if (curLevel < 5)
|
||||
{
|
||||
toolStripButton4.Enabled = false;
|
||||
cmbUser.Enabled = false;
|
||||
tbProcess.Enabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//var userList = FCOMMON.DBM.getGroupList("name + '(' + id + ')'", "Users", "[level] > 0 and [level] < 10", false, false);
|
||||
|
||||
781
SubProject/FPJ0000/dsQuery.Designer.cs
generated
781
SubProject/FPJ0000/dsQuery.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,31 @@ ORDER BY projectName</CommandText>
|
||||
</Mappings>
|
||||
<Sources />
|
||||
</TableAdapter>
|
||||
<TableAdapter BaseClass="System.ComponentModel.Component" DataAccessorModifier="AutoLayout, AnsiClass, Class, Public" DataAccessorName="HolydayUserListTableAdapter" GeneratorDataComponentClassName="HolydayUserListTableAdapter" Name="HolydayUserList" UserDataComponentName="HolydayUserListTableAdapter">
|
||||
<MainSource>
|
||||
<DbSource ConnectionRef="gwcs (Settings)" DbObjectName="EE.dbo.Holyday" DbObjectType="Table" FillMethodModifier="Public" FillMethodName="Fill" GenerateMethods="Both" GenerateShortCommands="false" GeneratorGetMethodName="GetData" GeneratorSourceName="Fill" GetMethodModifier="Public" GetMethodName="GetData" QueryType="Rowset" ScalarCallRetval="System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" UseOptimisticConcurrency="true" UserGetMethodName="GetData" UserSourceName="Fill">
|
||||
<SelectCommand>
|
||||
<DbCommand CommandType="Text" ModifiedByUser="true">
|
||||
<CommandText>SELECT uid, dbo.getUserName(uid) AS UserName
|
||||
FROM Holyday WITH (NOLOCK)
|
||||
WHERE (gcode = @gcode) AND (sdate >= @sd) AND (sdate <= @ed)
|
||||
GROUP BY uid
|
||||
ORDER BY UserName</CommandText>
|
||||
<Parameters>
|
||||
<Parameter AllowDbNull="false" AutogeneratedName="gcode" ColumnName="gcode" DataSourceName="EE.dbo.Holyday" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@gcode" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="gcode" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="sd" ColumnName="sdate" DataSourceName="EE.dbo.Holyday" DataTypeServer="date" DbType="AnsiString" Direction="Input" ParameterName="@sd" Precision="0" ProviderType="Date" Scale="0" Size="3" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
<Parameter AllowDbNull="true" AutogeneratedName="ed" ColumnName="sdate" DataSourceName="EE.dbo.Holyday" DataTypeServer="date" DbType="AnsiString" Direction="Input" ParameterName="@ed" Precision="0" ProviderType="Date" Scale="0" Size="3" SourceColumn="sdate" SourceColumnNullMapping="false" SourceVersion="Current" />
|
||||
</Parameters>
|
||||
</DbCommand>
|
||||
</SelectCommand>
|
||||
</DbSource>
|
||||
</MainSource>
|
||||
<Mappings>
|
||||
<Mapping SourceColumn="uid" DataSetColumn="uid" />
|
||||
<Mapping SourceColumn="UserName" DataSetColumn="UserName" />
|
||||
</Mappings>
|
||||
<Sources />
|
||||
</TableAdapter>
|
||||
</Tables>
|
||||
<Sources>
|
||||
<DbSource ConnectionRef="gwcs (Settings)" DbObjectType="Unknown" GenerateShortCommands="true" GeneratorSourceName="CheckHoliday" MethodsParameterType="CLR" Modifier="Public" Name="CheckHoliday" QueryType="Scalar" ScalarCallRetval="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" UseOptimisticConcurrency="true" UserGetMethodName="GetDataBy" UserSourceName="CheckHoliday">
|
||||
@@ -51,21 +76,21 @@ WHERE (pdate = @pdate)</CommandText>
|
||||
</DataSource>
|
||||
</xs:appinfo>
|
||||
</xs:annotation>
|
||||
<xs:element name="dsQuery" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_UserDSName="dsQuery" msprop:Generator_DataSetName="dsQuery">
|
||||
<xs:element name="dsQuery" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="dsQuery" msprop:Generator_UserDSName="dsQuery">
|
||||
<xs:complexType>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="JobReportItemList" msprop:Generator_RowEvHandlerName="JobReportItemListRowChangeEventHandler" msprop:Generator_RowDeletedName="JobReportItemListRowDeleted" msprop:Generator_RowDeletingName="JobReportItemListRowDeleting" msprop:Generator_RowEvArgName="JobReportItemListRowChangeEvent" msprop:Generator_TablePropName="JobReportItemList" msprop:Generator_RowChangedName="JobReportItemListRowChanged" msprop:Generator_RowChangingName="JobReportItemListRowChanging" msprop:Generator_TableClassName="JobReportItemListDataTable" msprop:Generator_RowClassName="JobReportItemListRow" msprop:Generator_TableVarName="tableJobReportItemList" msprop:Generator_UserTableName="JobReportItemList">
|
||||
<xs:element name="JobReportItemList" msprop:Generator_TableClassName="JobReportItemListDataTable" msprop:Generator_RowEvArgName="JobReportItemListRowChangeEvent" msprop:Generator_TableVarName="tableJobReportItemList" msprop:Generator_TablePropName="JobReportItemList" msprop:Generator_RowDeletingName="JobReportItemListRowDeleting" msprop:Generator_RowChangingName="JobReportItemListRowChanging" msprop:Generator_RowDeletedName="JobReportItemListRowDeleted" msprop:Generator_RowEvHandlerName="JobReportItemListRowChangeEventHandler" msprop:Generator_UserTableName="JobReportItemList" msprop:Generator_RowChangedName="JobReportItemListRowChanged" msprop:Generator_RowClassName="JobReportItemListRow">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="pidx" msprop:Generator_ColumnPropNameInRow="pidx" msprop:Generator_ColumnPropNameInTable="pidxColumn" msprop:Generator_ColumnVarNameInTable="columnpidx" msprop:Generator_UserColumnName="pidx" type="xs:int" minOccurs="0" />
|
||||
<xs:element name="projectName" msprop:Generator_ColumnPropNameInRow="projectName" msprop:Generator_ColumnPropNameInTable="projectNameColumn" msprop:Generator_ColumnVarNameInTable="columnprojectName" msprop:Generator_UserColumnName="projectName" minOccurs="0">
|
||||
<xs:element name="pidx" msprop:Generator_ColumnVarNameInTable="columnpidx" msprop:Generator_ColumnPropNameInRow="pidx" msprop:Generator_ColumnPropNameInTable="pidxColumn" msprop:Generator_UserColumnName="pidx" type="xs:int" />
|
||||
<xs:element name="projectName" msprop:Generator_ColumnVarNameInTable="columnprojectName" msprop:Generator_ColumnPropNameInRow="projectName" msprop:Generator_ColumnPropNameInTable="projectNameColumn" msprop:Generator_UserColumnName="projectName">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="255" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="pdate" msdata:ReadOnly="true" msprop:Generator_ColumnPropNameInRow="pdate" msprop:Generator_ColumnPropNameInTable="pdateColumn" msprop:Generator_ColumnVarNameInTable="columnpdate" msprop:Generator_UserColumnName="pdate" minOccurs="0">
|
||||
<xs:element name="pdate" msdata:ReadOnly="true" msprop:Generator_ColumnVarNameInTable="columnpdate" msprop:Generator_ColumnPropNameInRow="pdate" msprop:Generator_ColumnPropNameInTable="pdateColumn" msprop:Generator_UserColumnName="pdate" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10" />
|
||||
@@ -75,6 +100,26 @@ WHERE (pdate = @pdate)</CommandText>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="HolydayUserList" msprop:Generator_TableClassName="HolydayUserListDataTable" msprop:Generator_TableVarName="tableHolydayUserList" msprop:Generator_TablePropName="HolydayUserList" msprop:Generator_RowDeletingName="HolydayUserListRowDeleting" msprop:Generator_RowChangingName="HolydayUserListRowChanging" msprop:Generator_RowEvHandlerName="HolydayUserListRowChangeEventHandler" msprop:Generator_RowDeletedName="HolydayUserListRowDeleted" msprop:Generator_UserTableName="HolydayUserList" msprop:Generator_RowChangedName="HolydayUserListRowChanged" msprop:Generator_RowEvArgName="HolydayUserListRowChangeEvent" msprop:Generator_RowClassName="HolydayUserListRow">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="uid" msprop:Generator_ColumnVarNameInTable="columnuid" msprop:Generator_ColumnPropNameInRow="uid" msprop:Generator_ColumnPropNameInTable="uidColumn" msprop:Generator_UserColumnName="uid">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="20" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="UserName" msdata:ReadOnly="true" msprop:Generator_ColumnVarNameInTable="columnUserName" msprop:Generator_ColumnPropNameInRow="UserName" msprop:Generator_ColumnPropNameInTable="UserNameColumn" msprop:Generator_UserColumnName="UserName" minOccurs="0">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="200" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
|
||||
@@ -82,5 +127,9 @@ WHERE (pdate = @pdate)</CommandText>
|
||||
<xs:field xpath="mstns:pidx" />
|
||||
<xs:field xpath="mstns:projectName" />
|
||||
</xs:unique>
|
||||
<xs:unique name="HolydayUserList_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true">
|
||||
<xs:selector xpath=".//mstns:HolydayUserList" />
|
||||
<xs:field xpath="mstns:uid" />
|
||||
</xs:unique>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@@ -6,8 +6,9 @@
|
||||
</autogenerated>-->
|
||||
<DiagramLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ex:showrelationlabel="False" ViewPortX="0" ViewPortY="0" xmlns:ex="urn:schemas-microsoft-com:xml-msdatasource-layout-extended" xmlns="urn:schemas-microsoft-com:xml-msdatasource-layout">
|
||||
<Shapes>
|
||||
<Shape ID="DesignTable:JobReportItemList" ZOrder="2" X="40" Y="54" Height="305" Width="216" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="178" />
|
||||
<Shape ID="DesignSources:QueriesTableAdapter" ZOrder="1" X="392" Y="70" Height="220" Width="189" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="216" />
|
||||
<Shape ID="DesignTable:JobReportItemList" ZOrder="3" X="40" Y="54" Height="305" Width="216" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="178" />
|
||||
<Shape ID="DesignSources:QueriesTableAdapter" ZOrder="2" X="392" Y="70" Height="220" Width="189" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="216" />
|
||||
<Shape ID="DesignTable:HolydayUserList" ZOrder="1" X="260" Y="379" Height="115" Width="209" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="64" />
|
||||
</Shapes>
|
||||
<Connectors />
|
||||
</DiagramLayout>
|
||||
1
run_claude.bat
Normal file
1
run_claude.bat
Normal file
@@ -0,0 +1 @@
|
||||
claude --dangerously-skip-permissions
|
||||
Reference in New Issue
Block a user