| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- <!DOCTYPE html>
- <html lang="zh">
- <head>
- <meta charset="UTF-8">
- <title>质量巡检单生成助手</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
- <link rel="stylesheet" href="/public/css/wap/main.css">
- <link rel="stylesheet" href="/public/css/toast.css">
- <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
- <link rel="stylesheet" href="/public/css/toastr.css">
- <link rel="shortcut icon" href="/public/images/favicon.ico">
- <style>
- body,
- html {
- height: 100%;
- overflow: hidden;
- margin: 0; /* 去掉默认 margin */
- padding: 0;
- -webkit-overflow-scrolling: touch;
- }
- body {
- background: #f1f3f5;
- font-size: 16px;
- padding-bottom: 100px;
- }
- .chat-box {
- height: calc(100vh - 100px); /* 减去头部和底部高度,150px 是示例,需根据实际调整 */
- overflow-y: auto;
- /*padding: 10px;*/
- box-sizing: border-box;
- }
- .message {
- display: flex;
- margin-bottom: 12px;
- padding: 0 15px;
- }
- .message.user {
- justify-content: flex-end;
- }
- .message.ai {
- justify-content: flex-start;
- }
- .bubble {
- max-width: 95%;
- padding: 10px 14px;
- border-radius: 18px;
- line-height: 1.4;
- word-wrap: break-word;
- }
- .message.user .bubble {
- background: #007bff;
- color: white;
- border-bottom-right-radius: 0;
- }
- .message.ai .bubble {
- background: #dee2e6;
- color: #333;
- border-bottom-left-radius: 0;
- }
- .chat-footer {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- width: 100%;
- background: #fff;
- padding: 22px env(safe-area-inset-right) calc(10px + env(safe-area-inset-bottom)) env(safe-area-inset-left);
- box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.1);
- z-index: 999;
- }
- .chat-footer .input-group {
- bottom: 22px;
- }
- .chat-footer input.form-control {
- border: none;
- padding: 10px 12px;
- height: 44px;
- }
- .chat-footer .btn {
- border-radius: 0;
- }
- .form-preview {
- background: #fff;
- border: 1px solid #dee2e6;
- border-radius: 12px;
- padding: 15px 20px;
- margin: 20px 15px 0 15px;
- box-shadow: 0 2px 6px rgba(0,0,0,0.05);
- }
- .form-preview h6 {
- font-weight: bold;
- margin-bottom: 16px;
- border-bottom: 1px solid #dee2e6;
- padding-bottom: 8px;
- font-size: 17px;
- }
- .form-item {
- margin-bottom: 12px;
- font-size: 15px;
- line-height: 1.5;
- }
- .form-item label {
- font-weight: 500;
- color: #555;
- }
- .form-item span {
- display: inline-block;
- margin-left: 5px;
- color: #333;
- }
- .form-actions {
- border-top: 1px solid #dee2e6;
- padding-top: 12px;
- margin-top: 16px;
- display: flex;
- justify-content: space-between;
- }
- /* 1. WebKit 浏览器(Chrome, Safari, Android) */
- #chat-box::-webkit-scrollbar {
- width: 4px;
- }
- #chat-box::-webkit-scrollbar-track {
- background: transparent;
- }
- #chat-box::-webkit-scrollbar-thumb {
- background-color: rgba(0, 0, 0, 0.3);
- border-radius: 4px;
- }
- /* 2. Firefox */
- #chat-box {
- scrollbar-width: thin;
- scrollbar-color: rgba(0, 0, 0, 0.3) transparent;
- }
- /* 3. 选项:在小屏上彻底隐藏滚动条(可滑动但看不见) */
- @media (max-width: 768px) {
- #chat-box::-webkit-scrollbar {
- display: none;
- }
- #chat-box {
- -ms-overflow-style: none; /* IE 10+ */
- scrollbar-width: none; /* Firefox */
- }
- }
- .input-group {
- position: relative;
- }
- .input-icon {
- position: absolute;
- right: 75px; /* 根据按钮宽度调整 */
- top: 50%;
- transform: translateY(-50%);
- cursor: pointer;
- color: #888;
- z-index: 10;
- }
- #voice-icon.active {
- color: #007bff;
- }
- .xj-title {
- position: sticky;
- top: 0;
- background: #fff;
- }
- #recording-toast {
- position: fixed;
- bottom: 80px;
- left: 50%;
- transform: translateX(-50%);
- background-color: rgba(0, 0, 0, 0.85);
- color: #fff;
- padding: 12px 20px;
- border-radius: 24px;
- font-size: 14px;
- display: flex;
- align-items: center;
- z-index: 9999;
- animation: fadeInUp 0.3s ease-out;
- }
- #recording-toast .fa {
- margin-right: 8px;
- }
- @keyframes fadeInUp {
- from {
- opacity: 0;
- transform: translate(-50%, 100%);
- }
- to {
- opacity: 1;
- transform: translate(-50%, 0);
- }
- }
- </style>
- </head>
- <body>
- <div class="container mb-3 px-0">
- <h5 class="text-center py-2 xj-title mb-0">质量巡检单生成助手</h5>
- <div id="chat-box" class="chat-box mb-3">
- <div id="messages"></div>
- <!-- 表单预览卡片 -->
- <div id="form-preview" class="form-preview d-none">
- <h6><i class="fa fa-clipboard-check mr-2"></i>巡检单信息确认</h6>
- <div class="form-item">
- <label>检查项目:</label>
- <span id="field-check_item">—</span>
- </div>
- <div class="form-item">
- <label>现场检查情况:</label>
- <span id="field-check_situation">—</span>
- </div>
- <div class="form-item">
- <label>处理要求及措施:</label>
- <span id="field-action">—</span>
- </div>
- <div class="form-item">
- <label>检查日期:</label>
- <span id="field-date">—</span>
- </div>
- <div class="form-item">
- <label>质检员:</label>
- <span id="field-inspector">—</span>
- </div>
- <div class="form-actions">
- <button id="modify-btn" class="btn btn-outline-secondary btn-sm">
- <i class="fa fa-edit"></i> 修改
- </button>
- <button id="confirm-btn" class="btn btn-success btn-sm">
- <i class="fa fa-check-circle"></i> 确认生成
- </button>
- </div>
- </div>
- </div>
- <div class="chat-footer">
- <div class="input-group">
- <input type="text" id="user-input" class="form-control" placeholder="请输入...">
- <div class="input-icon">
- <i id="voice-icon" class="fa fa-microphone"></i>
- </div>
- <div class="input-group-append">
- <button class="btn btn-primary btn-send" id="send-btn">发送</button>
- </div>
- </div>
- </div>
- </div>
- <div id="recording-toast" style="display: none;">
- <div class="toast-inner">
- <i class="fa fa-microphone"></i>
- <span>正在录音,请讲话...</span>
- </div>
- </div>
- <script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
- <script src="/public/js/popper/popper.min.js"></script>
- <script src="/public/js/bootstrap/bootstrap.min.js"></script>
- <script src="/public/js/toastr.min.js"></script>
- <script src="/public/js/cookies.js"></script>
- <script src="/public/js/wap/global.js"></script>
- <script>
- const csrf = '<%= ctx.csrf %>';
- </script>
- <script>
- const $chatBox = $('#chat-box');
- const $formPreview = $('#form-preview');
- let conversationId = '';
- $(function () {
- const appendMessage = (text, sender = 'user', cssClass = '') => {
- const formatted = text.replace(/\n/g, '<br>');
- const $message = $('<div class="message"></div>').addClass(sender);
- if (cssClass) {
- $message.addClass(cssClass);
- }
- const $bubble = $('<div class="bubble"></div>').html(formatted);
- $message.append($bubble);
- $('#messages').append($message);
- $chatBox.scrollTop($chatBox[0].scrollHeight);
- };
- appendMessage("👋 嗨,我是质量巡检单生成助手,告诉我项目名称可以帮你快速生成巡检单", "ai", 'mt-3');
- const updatePreviewForm = (data) => {
- $('#field-check_item').text(data.check_item || '—');
- $('#field-check_situation').text(data.check_situation || '—');
- $('#field-action').text(data.action || '—');
- $('#field-date').text(data.date || '—');
- $('#field-inspector').text(data.inspector || '—');
- $formPreview.removeClass('d-none');
- };
- $('#send-btn').on('click', () => {
- const input = $('#user-input').val().trim();
- if (!input) return;
- appendMessage(input, 'user');
- $('#user-input').val('');
- $formPreview.addClass('d-none');
- postData('/wap/inspection/ask', { user_input: input, conversationId }, function (result) {
- if (result) {
- conversationId = result.conversation_id;
- if (result.answer_text) {
- appendMessage(result.answer_text, 'ai');
- }
- if (result.answer_json) {
- updatePreviewForm(result.answer_json);
- $formPreview.removeClass('d-none');
- } else {
- $formPreview.addClass('d-none');
- }
- } else {
- appendMessage('请求出错,请稍后重试。', 'ai');
- }
- }, function () {
- appendMessage('请求出错,请再输入一次。', 'ai');
- });
- });
- $('#user-input').on('keypress', function(e) {
- if (e.which === 13) $('#send-btn').click();
- });
- $('#confirm-btn').on('click', () => {
- alert('✅ 表单已提交!你可以跳转页面或保存到数据库');
- // 可跳转页面如 window.location.href = '/form/preview';
- });
- $('#modify-btn').on('click', () => {
- $formPreview.addClass('d-none');
- appendMessage('请继续修改你想调整的信息。', 'ai');
- });
- const originalHeight = window.innerHeight;
- $('#user-input').on('focus', function () {
- const $input = $(this);
- const checkKeyboardOpen = function () {
- const newHeight = window.innerHeight;
- if (newHeight < originalHeight) {
- // 键盘已弹出
- setTimeout(function () {
- $input[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
- }, 100);
- $(window).off('resize', checkKeyboardOpen);
- }
- };
- $(window).on('resize', checkKeyboardOpen);
- });
- const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
- recognition.continuous = false;
- recognition.lang = 'zh-CN';
- recognition.interimResults = false;
- let isRecording = false;
- let pressTimer = null;
- $('#voice-icon').on('touchstart', function (e) {
- e.preventDefault();
- $(this).addClass('active');
- // if (!isRecording) {
- // recognition.start();
- // $(this).addClass('active');
- // $('#recording-toast').fadeIn(); // 👉 显示录音提示
- // isRecording = true;
- // }
- pressTimer = setTimeout(() => {
- recognition.start();
- isRecording = true;
- $('#recording-toast').fadeIn(); // 👉 显示录音提示
- }, 300); // 按住 300ms 开始录音,可根据体验调整
- });
- $('#voice-icon').on('touchend touchcancel', function (e) {
- e.preventDefault();
- clearTimeout(pressTimer);
- if (isRecording) {
- recognition.stop();
- isRecording = false;
- $('#recording-toast').fadeOut(); // 👉 隐藏录音提示
- }
- $(this).removeClass('active');
- });
- recognition.onresult = function (event) {
- const result = event.results[0][0].transcript.trim();
- $('#user-input').val(result);
- };
- recognition.onerror = function (err) {
- console.error('语音识别出错:', err);
- $('#voice-icon').removeClass('active');
- $('#recording-toast').fadeOut(); // 👉 出错时也隐藏
- isRecording = false;
- };
- recognition.onend = function () {
- $('#voice-icon').removeClass('active');
- $('#recording-toast').fadeOut(); // 👉 识别结束时隐藏
- isRecording = false;
- };
- if (isWeChat()) {
- $('#voice-icon').hide(); // 在微信内隐藏语音按钮
- }
- });
- function isWeChat() {
- const ua = navigator.userAgent.toLowerCase();
- return /micromessenger/.test(ua);
- }
- </script>
- </body>
- </html>
|